{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/pinecone-io/examples/blob/master/learn/generation/langchain/langgraph/01-gpt-4o-research-agent.ipynb) [![Open nbviewer](https://raw.githubusercontent.com/pinecone-io/examples/master/assets/nbviewer-shield.svg)](https://nbviewer.org/github/pinecone-io/examples/blob/master/learn/generation/langchain/langgraph/01-gpt-4o-research-agent.ipynb)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_PFp0JhOWCU5"
      },
      "source": [
        "# GPT-4o Research Agent in LangGraph"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "EckNKuhXWHEJ"
      },
      "source": [
        "**Research agents** are multi-step LLM agents that through multiple steps can produce in depth research reports on a topic of our choosing. Most research agents are packed up into their own frameworks, like BlockAGI and others.\n",
        "\n",
        "In this example, we want to demonstrate how we can build our own AI research agent using `gpt-4o`, Pinecone, LangGraph, arXiv, and Google via the SerpAPI."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "TCVLlfNyAtxD",
        "outputId": "658c89aa-52b6-4663-cfb7-1391d2a1170d"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Reading package lists... Done\n",
            "Building dependency tree... Done\n",
            "Reading state information... Done\n",
            "pkg-config is already the newest version (0.29.2-1ubuntu3).\n",
            "graphviz is already the newest version (2.42.2-6).\n",
            "libgraphviz-dev is already the newest version (2.42.2-6).\n",
            "The following packages were automatically installed and are no longer required:\n",
            "  libbz2-dev libpkgconf3 libreadline-dev\n",
            "Use 'apt autoremove' to remove them.\n",
            "0 upgraded, 0 newly installed, 0 to remove and 45 not upgraded.\n"
          ]
        }
      ],
      "source": [
        "!apt-get install graphviz libgraphviz-dev pkg-config"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "X3hzHJ4NoLYD"
      },
      "source": [
        "We need these prerequisite libraries to run a graph visualization library (`pygraphviz`). We will use this library during this notebook to understand the structure of our graphs _but_ it is not required to use `langgraph`."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IbR8rt-EtqWh"
      },
      "source": [
        "Now we install Python libraries:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "FUt2EoJZu6M3"
      },
      "outputs": [],
      "source": [
        "!pip install -qU \\\n",
        "    datasets==2.19.1 \\\n",
        "    langchain-pinecone==0.1.1 \\\n",
        "    langchain-openai==0.1.9 \\\n",
        "    langchain==0.2.5 \\\n",
        "    langchain-core==0.2.9 \\\n",
        "    langgraph==0.1.1 \\\n",
        "    semantic-router==0.0.48 \\\n",
        "    serpapi==0.1.5 \\\n",
        "    google-search-results==2.4.2 \\\n",
        "    pygraphviz==1.12  # for visualizing"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bABCOVLFdrW4"
      },
      "source": [
        "## Research Agent Overview"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_t1rZK3FdtLh"
      },
      "source": [
        "Our research agent will consist of a function calling AI agent that has access to several tools that it can use to find information on a particular topic. It will be able to use several tools over multiple steps, meaning it can find information on one topic, broaden the scope of knowledge on this topic and _even_ investigate parallel topics where relevant.\n",
        "\n",
        "The tools we will be using are:\n",
        "\n",
        "* **ArXiv paper fetch**: Given an arXiv paper ID, this tool provides our agent with the abstract of the paper.\n",
        "* **Web search**: This tool provides our agent with access to Google search for more generalized queries.\n",
        "* **RAG search**: We will create a knowledge base containing AI arXiv papers. This tool provides our agent with access to this knowledge.\n",
        "* **RAG search with filter**: Sometimes our agent may need more information from a specific paper, this tool allows our agent to do just that.\n",
        "* **Final answer**: We create a custom final answer tool that forces our agent to output information in a specific format like:\n",
        "\n",
        "```\n",
        "INTRODUCTION\n",
        "------------\n",
        "<some intro to our report>\n",
        "\n",
        "RESEARCH STEPS\n",
        "--------------\n",
        "<the steps the agent took during research>\n",
        "\n",
        "REPORT\n",
        "------\n",
        "<the report main body>\n",
        "\n",
        "CONCLUSION\n",
        "----------\n",
        "<the report conclusion>\n",
        "\n",
        "SOURCES\n",
        "-------\n",
        "<any sources the agent used>\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vovHYoM-AdbU"
      },
      "source": [
        "## Setup Knowledge Base"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YEtKvy4_AgLy"
      },
      "source": [
        "We'll be running our agent against a knowledge base \u2014 which requires a Pinecone index to be built.\n",
        "\n",
        "You can, if needed, skip this step and replace the `search` tool with a placeholder value if wanting to quickly test the structure of a RAG agent _without_ the RAG.\n",
        "\n",
        "If you want full functionality here, you do need to run this section \u2014 but we'll make it quick."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ohBxmFyTBFT0"
      },
      "source": [
        "### Download a Dataset"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "g1ufvA8hBKHx"
      },
      "source": [
        "The first thing we need for an agent using RAG is somewhere we want to pull knowledge from. We will use v2 of the AI ArXiv dataset, available on Hugging Face Datasets at [`jamescalam/ai-arxiv2-chunks`](https://huggingface.co/datasets/jamescalam/ai-arxiv2-chunks).\n",
        "\n",
        "Note: we're using the prechunked dataset. For the raw version see [`jamescalam/ai-arxiv2`](https://huggingface.co/datasets/jamescalam/ai-arxiv2)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "ehcjNQ49BBuI",
        "outputId": "9b05f125-f2cd-4cf0-b6fd-a84d5a73b974"
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "/usr/local/lib/python3.10/dist-packages/huggingface_hub/utils/_token.py:89: UserWarning: \n",
            "The secret `HF_TOKEN` does not exist in your Colab secrets.\n",
            "To authenticate with the Hugging Face Hub, create a token in your settings tab (https://huggingface.co/settings/tokens), set it as secret in your Google Colab and restart your session.\n",
            "You will be able to reuse this secret in all of your notebooks.\n",
            "Please note that authentication is recommended but still optional to access public models or datasets.\n",
            "  warnings.warn(\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "Dataset({\n",
              "    features: ['id', 'title', 'content', 'prechunk_id', 'postchunk_id', 'arxiv_id', 'references'],\n",
              "    num_rows: 209760\n",
              "})"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from datasets import load_dataset\n",
        "\n",
        "dataset = load_dataset(\"jamescalam/ai-arxiv2-semantic-chunks\", split=\"train\")\n",
        "dataset"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "pElKCcVSSddB",
        "outputId": "91378db1-cec5-4d65-d872-bdd6e77f822a"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'id': '2401.04088#0',\n",
              " 'title': 'Mixtral of Experts',\n",
              " 'content': '4 2 0 2 n a J 8 ] G L . s c [ 1 v 8 8 0 4 0 . 1 0 4 2 : v i X r a # Mixtral of Experts Albert Q. Jiang, Alexandre Sablayrolles, Antoine Roux, Arthur Mensch, Blanche Savary, Chris Bamford, Devendra Singh Chaplot, Diego de las Casas, Emma Bou Hanna, Florian Bressand, Gianna Lengyel, Guillaume Bour, Guillaume Lample, L\u00c3\u00a9lio Renard Lavaud, Lucile Saulnier, Marie-Anne Lachaux, Pierre Stock, Sandeep Subramanian, Sophia Yang, Szymon Antoniak, Teven Le Scao, Th\u00c3\u00a9ophile Gervet, Thibaut Lavril, Thomas Wang, Timoth\u00c3\u00a9e Lacroix, William El Sayed Abstract We introduce Mixtral 8x7B, a Sparse Mixture of Experts (SMoE) language model. Mixtral has the same architecture as Mistral 7B, with the difference that each layer is composed of 8 feedforward blocks (i.e. experts). For every token, at each layer, a router network selects two experts to process the current state and combine their outputs. Even though each token only sees two experts, the selected experts can be different at each timestep. As a result, each token has access to 47B parameters, but only uses 13B active parameters during inference. Mixtral was trained with a context size of 32k tokens and it outperforms or matches Llama 2 70B and GPT-3.5 across all evaluated benchmarks. In particular, Mixtral vastly outperforms Llama 2 70B on mathematics, code generation, and multilingual benchmarks. We also provide a model fine- tuned to follow instructions, Mixtral 8x7B \u00e2 Instruct, that surpasses GPT-3.5 Turbo, Claude-2.1, Gemini Pro, and Llama 2 70B \u00e2 chat model on human bench- marks. Both the base and instruct models are released under the Apache 2.0 license.',\n",
              " 'prechunk_id': '',\n",
              " 'postchunk_id': '2401.04088#1',\n",
              " 'arxiv_id': '2401.04088',\n",
              " 'references': ['1905.07830']}"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "dataset[0]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vJjZMEO_HmOi"
      },
      "source": [
        "Building a knowledge base:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LjsIFVbtKBu4"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "from getpass import getpass\n",
        "from semantic_router.encoders import OpenAIEncoder\n",
        "\n",
        "os.environ[\"OPENAI_API_KEY\"] = os.getenv(\"OPENAI_API_KEY\") or getpass(\"OpenAI API key: \")\n",
        "\n",
        "encoder = OpenAIEncoder(name=\"text-embedding-3-small\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "J233t2I4HmjD"
      },
      "outputs": [],
      "source": [
        "from pinecone import Pinecone\n",
        "\n",
        "# initialize connection to pinecone (get API key at app.pinecone.io)\n",
        "api_key = os.getenv(\"PINECONE_API_KEY\") or getpass(\"Pinecone API key: \")\n",
        "\n",
        "# configure client\n",
        "pc = Pinecone(api_key=api_key)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "actWflaEKgVb"
      },
      "outputs": [],
      "source": [
        "from pinecone import ServerlessSpec\n",
        "\n",
        "spec = ServerlessSpec(\n",
        "    cloud=\"aws\", region=\"us-west-2\"  # us-east-1\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "jWijfk8LKil7",
        "outputId": "44740df7-25b2-455f-9856-bd24e8f11b1d"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "1536"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "dims = len(encoder([\"some random text\"])[0])\n",
        "dims"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "V-GHzWs3KlJn",
        "outputId": "8636719c-ae83-451b-e230-f2bb209d67a9"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'dimension': 1536,\n",
              " 'index_fullness': 0.0,\n",
              " 'namespaces': {'': {'vector_count': 10000}},\n",
              " 'total_vector_count': 10000}"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import time\n",
        "\n",
        "index_name = \"gpt-4o-research-agent\"\n",
        "\n",
        "# check if index already exists (it shouldn't if this is first time)\n",
        "if index_name not in pc.list_indexes().names():\n",
        "    # if does not exist, create index\n",
        "    pc.create_index(\n",
        "        index_name,\n",
        "        dimension=dims,  # dimensionality of embed 3\n",
        "        metric='dotproduct',\n",
        "        spec=spec\n",
        "    )\n",
        "    # wait for index to be initialized\n",
        "    while not pc.describe_index(index_name).status['ready']:\n",
        "        time.sleep(1)\n",
        "\n",
        "# connect to index\n",
        "index = pc.Index(index_name)\n",
        "time.sleep(1)\n",
        "# view index stats\n",
        "index.describe_index_stats()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vwNPeBbZK0hx"
      },
      "source": [
        "Populate our knowledge base:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 69,
          "referenced_widgets": [
            "925f65b6b0cc47be803c021f644a8f84",
            "24a571b8cc864f60bea7ae90ef331b21",
            "45580486ce0742b29d0de17850c42060",
            "f1f07bc63a234590ac229d63217e197a",
            "a6d67d04d1c8432c8840f411027a0e79",
            "c52a55d3643b4f1c83bdf1b1b5fce242",
            "7de73bce9c0540e2b3b2c599d57ae215",
            "84c25583658a4f4caeedbc19dd29457a",
            "a9594c4de9734895862a48f90bc8c621",
            "48ec484f11324501b1020314d4989da6",
            "bfecdc3138334cd1adcd055f338060d1"
          ]
        },
        "id": "5iQ2YJPeK2Us",
        "outputId": "823fcf4f-3735-4a85-e041-0b87df7bdb56"
      },
      "outputs": [
        {
          "data": {
            "application/vnd.jupyter.widget-view+json": {
              "model_id": "925f65b6b0cc47be803c021f644a8f84",
              "version_major": 2,
              "version_minor": 0
            },
            "text/plain": [
              "  0%|          | 0/79 [00:00<?, ?it/s]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "from tqdm.auto import tqdm\n",
        "\n",
        "# easier to work with dataset as pandas dataframe\n",
        "data = dataset.to_pandas().iloc[:10000]\n",
        "\n",
        "batch_size = 128\n",
        "\n",
        "for i in tqdm(range(0, len(data), batch_size)):\n",
        "    i_end = min(len(data), i+batch_size)\n",
        "    batch = data[i:i_end].to_dict(orient=\"records\")\n",
        "    # get batch of data\n",
        "    metadata = [{\n",
        "        \"title\": r[\"title\"],\n",
        "        \"content\": r[\"content\"],\n",
        "        \"arxiv_id\": r[\"arxiv_id\"],\n",
        "        \"references\": r[\"references\"].tolist()\n",
        "    } for r in batch]\n",
        "    # generate unique ids for each chunk\n",
        "    ids = [r[\"id\"] for r in batch]\n",
        "    # get text content to embed\n",
        "    content = [r[\"content\"] for r in batch]\n",
        "    # embed text\n",
        "    embeds = encoder(content)\n",
        "    # add to Pinecone\n",
        "    index.upsert(vectors=zip(ids, embeds, metadata))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hITmdwQ7Qns0"
      },
      "source": [
        "## Graph State\n",
        "\n",
        "We will define a custom graph state to support our agent-oriented decision making."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "x7Fj9KNjQvUq"
      },
      "outputs": [],
      "source": [
        "from typing import TypedDict, Annotated, List, Union\n",
        "from langchain_core.agents import AgentAction, AgentFinish\n",
        "from langchain_core.messages import BaseMessage\n",
        "import operator\n",
        "\n",
        "\n",
        "class AgentState(TypedDict):\n",
        "    input: str\n",
        "    chat_history: list[BaseMessage]\n",
        "    intermediate_steps: Annotated[list[tuple[AgentAction, str]], operator.add]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Fp4uQFBKQdyI"
      },
      "source": [
        "There are four parts to our agent state, those are:\n",
        "\n",
        "* `input`: this is the user's most recent query, usually this would be a question that we want to answer with our research agent.\n",
        "* `chat_history`: we are building a conversational agent that can support multiple interactions, to allow previous interactions to provide additional context throughout our agent logic we include the chat history in the agent state.\n",
        "* `intermediate_steps`: provides a record of all steps the research agent will take between the user asking a question via `input` and the agent providing a final answer. This can include things like \"search arxiv\", \"perform general purpose web search\", etc. These intermediate steps are crucial to allowing the agent to follow a path of coherent actions and ultimately producing an informed final answer."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zlVbgX39Rhxj"
      },
      "source": [
        "## Custom Tools"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "io-lnbpgKHzy"
      },
      "source": [
        "We will define several tools for this agent that will focus on initial data discovery, that will allow the LLM to use more tools to research more deeply via a variety of different routes."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v9MYnZvtF9WN"
      },
      "source": [
        "### ArXiv Paper Fetch"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VQZjy5TZGAFB"
      },
      "source": [
        "The `fetch_arxiv` tool will allow our agent to get the summary of a specific paper given an ArXiv paper ID. To do this, we will simply send a GET request to arXiv and use regex to extract the paper abstract."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 159
        },
        "id": "B2W-V1cOGzwJ",
        "outputId": "37a39e8c-491c-448f-f0ba-86818e8353ca"
      },
      "outputs": [
        {
          "data": {
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            },
            "text/plain": [
              "'<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\">\\n<head>\\n<title>[2401.04088] Mixtral of Experts</title>\\n<link rel=\"shortcut icon\" href=\"/favicon.ico\" type=\"image/x-icon\" />\\n<link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\"/css/arXiv-export.css\" />\\n<link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\"/bibex/bibex.css?20181009\">\\n<link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\"https://static.arxiv.org/static/browse/0.3.8/css/browse_search.css\" />\\n<meta name=\"citation_title\" content=\"Mixtral of Experts\" />\\n<meta name=\"citation_author\" content=\"Jiang, Albert Q.\" />\\n<meta name=\"citation_author\" content=\"Sablayrolles, Alexandre\" />\\n<meta name=\"citation_author\" content=\"Roux, Antoine\" />\\n<meta name=\"citation_author\" content=\"Mensch, Arthur\" />\\n<meta name=\"citation_author\" content=\"Savary, Blanche\" />\\n<meta name=\"citation_author\" content=\"Bamford, Chris\" />\\n<meta name=\"citation_author\" content=\"Chaplot, Devendra Singh\" />\\n<meta name=\"citation_author\" content=\"Casas, Diego de las\" />\\n<meta name=\"citation_author\" content=\"Hanna, Emma Bou\" />\\n<meta name=\"citation_author\" content=\"Bressand, Florian\" />\\n<meta name=\"citation_author\" content=\"Lengyel, Gianna\" />\\n<meta name=\"citation_author\" content=\"Bour, Guillaume\" />\\n<meta name=\"citation_author\" content=\"Lample, Guillaume\" />\\n<meta name=\"citation_author\" content=\"Lavaud, L&#xe9;lio Renard\" />\\n<meta name=\"citation_author\" content=\"Saulnier, Lucile\" />\\n<meta name=\"citation_author\" content=\"Lachaux, Marie-Anne\" />\\n<meta name=\"citation_author\" content=\"Stock, Pierre\" />\\n<meta name=\"citation_author\" content=\"Subramanian, Sandeep\" />\\n<meta name=\"citation_author\" content=\"Yang, Sophia\" />\\n<meta name=\"citation_author\" content=\"Antoniak, Szymon\" />\\n<meta name=\"citation_author\" content=\"Scao, Teven Le\" />\\n<meta name=\"citation_author\" content=\"Gervet, Th&#xe9;ophile\" />\\n<meta name=\"citation_author\" content=\"Lavril, Thibaut\" />\\n<meta name=\"citation_author\" content=\"Wang, Thomas\" />\\n<meta name=\"citation_author\" content=\"Lacroix, Timoth&#xe9;e\" />\\n<meta name=\"citation_author\" content=\"Sayed, William El\" />\\n<meta name=\"citation_date\" content=\"2024/01/08\" />\\n<meta name=\"citation_online_date\" content=\"2024/01/08\" />\\n<meta name=\"citation_pdf_url\" content=\"http://arxiv.org/pdf/2401.04088\" />\\n<meta name=\"citation_arxiv_id\" content=\"2401.04088\" />\\n<script src=\"/js/mathjaxToggle.min.js\" type=\"text/javascript\"></script>\\n\\n\\n</head>\\n<body class=\"with-cu-identity\">\\n\\n<div id=\"cu-identity\">\\n<div id=\"cu-logo\">\\n<a href=\"https://www.cornell.edu/\"><img src=\"//static.arxiv.org/icons/cu/cornell-reduced-white-SMALL.svg\" alt=\"Cornell University\" width=\"200\" border=\"0\" /></a>\\n</div>\\n<div id=\"support-ack\">\\n<a href=\"https://confluence.cornell.edu/x/ALlRF\">We gratefully acknowledge support from<br /> the Simons Foundation and member institutions.</a>\\n</div>\\n</div>\\n<div id=\"header\">\\n<h1 class=\"header-breadcrumbs\"><a href=\"/\"><img src=\"//static.arxiv.org/images/arxiv-logo-one-color-white.svg\" aria-label=\"logo\" alt=\"arxiv logo\" width=\"85\" style=\"width:85px;margin-right:8px;\"></a> <span>&gt;</span> <a href=\"/list/cs/recent\">cs</a> <span>&gt;</span> arXiv:2401.04088</h1>\\n<div id=\"search\">\\n<form id=\"search-arxiv\" method=\"post\" action=\"/search_classic\">\\n\\n<div class=\"wrapper-search-arxiv\">\\n<input class=\"keyword-field\" type=\"text\" name=\"query\" placeholder=\"Search or Article ID\"/>\\n\\n<div class=\"filter-field\">\\n <select name=\"searchtype\">\\n<option value=\"all\" selected=\"selected\">All papers</option>\\n<option value=\"ti\">Titles</option>\\n<option value=\"au\">Authors</option>\\n<option value=\"abs\">Abstracts</option>\\n<option value=\"ft\">Full text</option>\\n</select>\\n</div>\\n<input class=\"btn-search-arxiv\" value=\"\" type=\"submit\">\\n<div class=\"links\">(<a href=\"https://info.arxiv.org/help\">Help</a> | <a href=\"/find\">Advanced search</a>)</div>\\n</div>\\n</form>\\n</div>\\n</div>\\n<div id=\"content\">\\n\\n<!--\\n<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\\n         xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\\n         xmlns:trackback=\"http://madskills.com/public/xml/rss/module/trackback/\">\\n    <rdf:Description\\n        rdf:about=\"http://arxiv.org/abs/2401.04088\"\\n        dc:identifier=\"http://arxiv.org/abs/2401.04088\"\\n        dc:title=\"Mixtral of Experts\"\\n        trackback:ping=\"http://arxiv.org/trackback/2401.04088\" />\\n    </rdf:RDF>\\n-->\\n\\n<div id=\"abs\">\\n<div class=\"extra-services\">\\n\\n<div class=\"full-text\">\\n<span class=\"descriptor\">Full-text links:</span>\\n<h2>Download:</h2>\\n<ul>\\n<li><a href=\"/pdf/2401.04088\" accesskey=\"f\">PDF</a></li>\\n<li><a href=\"/format/2401.04088\">Other formats</a></li>\\n</ul>\\n<div class=\"abs-license\"><a href=\"http://creativecommons.org/licenses/by/4.0/\" title=\"Rights to this article\"><img src=\"/icons/licenses/by-4.0.png\"/></a></div>\\n</div><!--end full-text-->\\n\\n<div class=\"browse\">\\n<h3>Current browse context:</h3>\\n<div class=\"current\">cs.LG</div>\\n<div class=\"prevnext\"><span class=\"arrow\"><a href=\"http://arxiv.org/prevnext?site=export.arxiv.org&amp;id=2401.04088&amp;context=cs.LG&amp;function=prev\" accesskey=\"p\" title=\"previous in cs.LG (accesskey p)\">&lt;&nbsp;prev</a></span>&nbsp;|&nbsp;<span class=\"arrow\"><a href=\"http://arxiv.org/prevnext?site=export.arxiv.org&amp;id=2401.04088&amp;context=cs.LG&amp;function=next\" accesskey=\"n\" title=\"next in cs.LG (accesskey n)\">next&nbsp;&gt;</a></span>\\n<br /></div>\\n<div class=\"list\"><a href=\"/list/cs.LG/new\">new</a>&nbsp;| <a href=\"/list/cs.LG/recent\">recent</a>&nbsp;| <a href=\"/list/cs.LG/2401\">2401</a></div><h3>Change to browse by:</h3><div class=\"switch\">\\n<a href=\"/abs/2401.04088?context=cs\">cs</a><br />\\n<span class=\"subclass\"><a href=\"/abs/2401.04088?context=cs.CL\">cs.CL</a></span>\\n</div>\\n\\n</div>\\n<div class=\"extra-ref-cite\">\\n<h3>References &amp; Citations</h3><ul><li><a href=\"http://adsabs.harvard.edu/cgi-bin/bib_query?arXiv:2401.04088\">NASA ADS</a></li>\\n</ul>\\n\\n</div>\\n<div class=\"dblp\">\\n<h3><a href=\"http://www.informatik.uni-trier.de/~ley/db/\">DBLP</a> - CS Bibliography</h3><div class=\"list\">\\n<a href=\"http://www.informatik.uni-trier.de/~ley/db/journals/corr/corr2401.html#abs-2401-04088\">listing</a> | <a href=\"http://dblp.uni-trier.de/rec/bibtex/journals/corr/abs-2401-04088\">bibtex</a>\\n</div>\\n\\n</div>\\n<div class=\"bookmarks\">\\n<div class=\"what-is-this\">\\n<h3>Bookmark</h3> (<a href=\"https://info.arxiv.org/help/social_bookmarking\">what is this?</a>)\\n</div>\\n<a href=\"http://arxiv.org/ct?url=http%3A%2F%2Fwww.citeulike.org%2Fposturl%3Furl%3Dhttp%3A%2F%2Farxiv.org%2Fabs%2F2401.04088%26title%3DMixtral%2520of%2520Experts%26authors%3D&amp;v=354d162e\" title=\"Bookmark on CiteULike\"><img src=\"//static.arxiv.org/icons/social/citeulike.png\" alt=\"CiteULike logo\" /></a>\\n<a href=\"http://arxiv.org/ct?url=http%3A%2F%2Fwww.bibsonomy.org%2FBibtexHandler%3FrequTask%3Dupload%26url%3Dhttp%3A%2F%2Farxiv.org%2Fabs%2F2401.04088%26description%3DMixtral%2520of%2520Experts&amp;v=bef47afc\" title=\"Bookmark on BibSonomy\"><img src=\"//static.arxiv.org/icons/social/bibsonomy.png\" alt=\"BibSonomy logo\" /></a>\\n<a href=\"http://arxiv.org/ct?url=https%3A%2F%2Fwww.mendeley.com%2Fimport%2F%3Furl%3Dhttp%3A%2F%2Farxiv.org%2Fabs%2F2401.04088&amp;v=be336fd9\" title=\"Bookmark on Mendeley\"><img src=\"//static.arxiv.org/icons/social/mendeley.png\" alt=\"Mendeley logo\" /></a>\\n<a href=\"http://arxiv.org/ct?url=https%3A%2F%2Fdel.icio.us%2Fpost%3Furl%3Dhttp%3A%2F%2Farxiv.org%2Fabs%2F2401.04088%26description%3DMixtral%2520of%2520Experts&amp;v=827de2f6\" title=\"Bookmark on del.icio.us\"><img src=\"//static.arxiv.org/icons/social/delicious.png\" alt=\"del.icio.us logo\" /></a>\\n<a href=\"http://arxiv.org/ct?url=https%3A%2F%2Fdigg.com%2Fsubmit%3Furl%3Dhttp%3A%2F%2Farxiv.org%2Fabs%2F2401.04088%26title%3DMixtral%2520of%2520Experts&amp;v=8d5c0d57\" title=\"Bookmark on Digg\"><img src=\"//static.arxiv.org/icons/social/digg.png\" alt=\"Digg logo\" /></a>\\n<a href=\"http://arxiv.org/ct?url=https%3A%2F%2Freddit.com%2Fsubmit%3Furl%3Dhttp%3A%2F%2Farxiv.org%2Fabs%2F2401.04088%26title%3DMixtral%2520of%2520Experts&amp;v=14eafc8c\" title=\"Bookmark on Reddit\"><img src=\"//static.arxiv.org/icons/social/reddit.png\" alt=\"Reddit logo\" /></a>\\n\\n</div>\\n</div><!--end extra-services-->\\n\\n<div class=\"leftcolumn\">\\n<div class=\"subheader\">\\n<h1>Computer Science > Machine Learning</h1>\\n</div>\\n<h1 class=\"title mathjax\"><span class=\"descriptor\">Title:</span>\\nMixtral of Experts</h1>\\n<div class=\"authors\"><span class=\"descriptor\">Authors:</span>\\n<a href=\"/find/cs/1/au:+Jiang_A/0/1/0/all/0/1\">Albert Q. Jiang</a>, \\n<a href=\"/find/cs/1/au:+Sablayrolles_A/0/1/0/all/0/1\">Alexandre Sablayrolles</a>, \\n<a href=\"/find/cs/1/au:+Roux_A/0/1/0/all/0/1\">Antoine Roux</a>, \\n<a href=\"/find/cs/1/au:+Mensch_A/0/1/0/all/0/1\">Arthur Mensch</a>, \\n<a href=\"/find/cs/1/au:+Savary_B/0/1/0/all/0/1\">Blanche Savary</a>, \\n<a href=\"/find/cs/1/au:+Bamford_C/0/1/0/all/0/1\">Chris Bamford</a>, \\n<a href=\"/find/cs/1/au:+Chaplot_D/0/1/0/all/0/1\">Devendra Singh Chaplot</a>, \\n<a href=\"/find/cs/1/au:+Casas_D/0/1/0/all/0/1\">Diego de las Casas</a>, \\n<a href=\"/find/cs/1/au:+Hanna_E/0/1/0/all/0/1\">Emma Bou Hanna</a>, \\n<a href=\"/find/cs/1/au:+Bressand_F/0/1/0/all/0/1\">Florian Bressand</a>, \\n<a href=\"/find/cs/1/au:+Lengyel_G/0/1/0/all/0/1\">Gianna Lengyel</a>, \\n<a href=\"/find/cs/1/au:+Bour_G/0/1/0/all/0/1\">Guillaume Bour</a>, \\n<a href=\"/find/cs/1/au:+Lample_G/0/1/0/all/0/1\">Guillaume Lample</a>, \\n<a href=\"/find/cs/1/au:+Lavaud_L/0/1/0/all/0/1\">L&#xe9;lio Renard Lavaud</a>, \\n<a href=\"/find/cs/1/au:+Saulnier_L/0/1/0/all/0/1\">Lucile Saulnier</a>, \\n<a href=\"/find/cs/1/au:+Lachaux_M/0/1/0/all/0/1\">Marie-Anne Lachaux</a>, \\n<a href=\"/find/cs/1/au:+Stock_P/0/1/0/all/0/1\">Pierre Stock</a>, \\n<a href=\"/find/cs/1/au:+Subramanian_S/0/1/0/all/0/1\">Sandeep Subramanian</a>, \\n<a href=\"/find/cs/1/au:+Yang_S/0/1/0/all/0/1\">Sophia Yang</a>, \\n<a href=\"/find/cs/1/au:+Antoniak_S/0/1/0/all/0/1\">Szymon Antoniak</a>, \\n<a href=\"/find/cs/1/au:+Scao_T/0/1/0/all/0/1\">Teven Le Scao</a>, \\n<a href=\"/find/cs/1/au:+Gervet_T/0/1/0/all/0/1\">Th&#xe9;ophile Gervet</a>, \\n<a href=\"/find/cs/1/au:+Lavril_T/0/1/0/all/0/1\">Thibaut Lavril</a>, \\n<a href=\"/find/cs/1/au:+Wang_T/0/1/0/all/0/1\">Thomas Wang</a>, \\n<a href=\"/find/cs/1/au:+Lacroix_T/0/1/0/all/0/1\">Timoth&#xe9;e Lacroix</a>, \\n<a href=\"/find/cs/1/au:+Sayed_W/0/1/0/all/0/1\">William El Sayed</a></div>\\n<div class=\"dateline\">(Submitted on 8 Jan 2024)</div>\\n<blockquote class=\"abstract mathjax\">\\n<span class=\"descriptor\">Abstract:</span> We introduce Mixtral 8x7B, a Sparse Mixture of Experts (SMoE) language model.\\nMixtral has the same architecture as Mistral 7B, with the difference that each\\nlayer is composed of 8 feedforward blocks (i.e. experts). For every token, at\\neach layer, a router network selects two experts to process the current state\\nand combine their outputs. Even though each token only sees two experts, the\\nselected experts can be different at each timestep. As a result, each token has\\naccess to 47B parameters, but only uses 13B active parameters during inference.\\nMixtral was trained with a context size of 32k tokens and it outperforms or\\nmatches Llama 2 70B and GPT-3.5 across all evaluated benchmarks. In particular,\\nMixtral vastly outperforms Llama 2 70B on mathematics, code generation, and\\nmultilingual benchmarks. We also provide a model fine-tuned to follow\\ninstructions, Mixtral 8x7B - Instruct, that surpasses GPT-3.5 Turbo,\\nClaude-2.1, Gemini Pro, and Llama 2 70B - chat model on human benchmarks. Both\\nthe base and instruct models are released under the Apache 2.0 license.\\n</blockquote>\\n<!--CONTEXT-->\\n<div class=\"metatable\">\\n<table summary=\"Additional metadata\">\\n<tr>\\n<td class=\"tablecell label\">Comments:\\n</td>\\n<td class=\"tablecell comments mathjax\">See more details at <a href=\"https://mistral.ai/news/mixtral-of-experts/\">this https URL</a></td>\\n</tr>\\n<tr>\\n<td class=\"tablecell label\">Subjects:\\n</td>\\n<td class=\"tablecell subjects\"><span class=\"primary-subject\">Machine Learning (cs.LG)</span>; Computation and Language (cs.CL)</td>\\n</tr>\\n<tr>\\n<td class=\"tablecell label\">\\nCite&nbsp;as:\\n</td>\\n<td class=\"tablecell arxivid\"><a href=\"/abs/2401.04088\">arXiv:2401.04088</a> [cs.LG]</td>\\n</tr>\\n<tr>\\n<td class=\"tablecell label\">&nbsp;</td>\\n<td class=\"tablecell arxividv\">(or <span class=\"arxivid\"><a href=\"/abs/2401.04088v1\">arXiv:2401.04088v1</a> [cs.LG]</span> for this version)</td>\\n</tr>\\n</table>\\n</div>\\n<div class=\"submission-history\">\\n<h2>Submission history</h2>\\nFrom: Devendra Singh Chaplot [<a href=\"https://arxiv.org/show-email/d382fa4f/2401.04088\">view email</a>]\\n<br />\\n<b>[v1]</b> Mon, 8 Jan 2024 18:47:34 GMT  (2811kb,D)<br />\\n</div>\\n<div class=\"endorsers\"><a href=\"http://arxiv.org/auth/show-endorsers/2401.04088\">Which authors of this paper are endorsers?</a> | <a id=\"mathjax_toggle\" href=\"javascript:setMathjaxCookie()\">Disable MathJax</a> (<a href=\"/help/mathjax\">What is MathJax?</a>) </div><script type=\"text/javascript\" language=\"javascript\">mathjaxToggle();</script>\\n<script src=\"/bibex/bibex.js?20181009\" type=\"text/javascript\" defer></script>\\n</div><!--end leftcolumn-->\\n</div><!--end abs-->\\n<p>Link back to: <a href=\"http://arXiv.org/\">arXiv</a>, <a href=\"http://arxiv.org/form\">form interface</a>, <a href=\"/help/contact\">contact</a>.</p>\\n</div>\\n</div>\\n <footer style=\"clear: both;\">\\n      <div class=\"columns is-desktop\" role=\"navigation\" aria-label=\"Secondary\" style=\"margin: -0.75em -0.75em 0.75em -0.75em\">\\n        <!-- Macro-Column 1 -->\\n        <div class=\"column\" style=\"padding: 0;\">\\n          <div class=\"columns\">\\n            <div class=\"column\">\\n              <ul style=\"list-style: none; line-height: 2;\">\\n                <li><a href=\"https://arxiv.org/about\">About</a></li>\\n                <li><a href=\"https://arxiv.org/help\">Help</a></li>\\n              </ul>\\n            </div>\\n            <div class=\"column\">\\n              <ul style=\"list-style: none; line-height: 2;\">\\n                <li>\\n                  <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\" class=\"icon filter-black\" role=\"presentation\"><title>contact arXiv</title><desc>Click here to contact arXiv</desc><path d=\"M502.3 190.8c3.9-3.1 9.7-.2 9.7 4.7V400c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V195.6c0-5 5.7-7.8 9.7-4.7 22.4 17.4 52.1 39.5 154.1 113.6 21.1 15.4 56.7 47.8 92.2 47.6 35.7.3 72-32.8 92.3-47.6 102-74.1 131.6-96.3 154-113.7zM256 320c23.2.4 56.6-29.2 73.4-41.4 132.7-96.3 142.8-104.7 173.4-128.7 5.8-4.5 9.2-11.5 9.2-18.9v-19c0-26.5-21.5-48-48-48H48C21.5 64 0 85.5 0 112v19c0 7.4 3.4 14.3 9.2 18.9 30.6 23.9 40.7 32.4 173.4 128.7 16.8 12.2 50.2 41.8 73.4 41.4z\"/></svg>\\n                  <a href=\"https://arxiv.org/help/contact\"> Contact</a>\\n                </li>\\n                <li>\\n                  <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\" class=\"icon filter-black\" role=\"presentation\"><title>subscribe to arXiv mailings</title><desc>Click here to subscribe</desc><path d=\"M476 3.2L12.5 270.6c-18.1 10.4-15.8 35.6 2.2 43.2L121 358.4l287.3-253.2c5.5-4.9 13.3 2.6 8.6 8.3L176 407v80.5c0 23.6 28.5 32.9 42.5 15.8L282 426l124.6 52.2c14.2 6 30.4-2.9 33-18.2l72-432C515 7.8 493.3-6.8 476 3.2z\"/></svg>\\n                  <a href=\"https://arxiv.org/help/subscribe\"> Subscribe</a>\\n                </li>\\n              </ul>\\n            </div>\\n          </div>\\n        </div>\\n        <!-- End Macro-Column 1 -->\\n        <!-- Macro-Column 2 -->\\n        <div class=\"column\" style=\"padding: 0;\">\\n          <div class=\"columns\">\\n            <div class=\"column\">\\n              <ul style=\"list-style: none; line-height: 2;\">\\n                <li><a href=\"https://arxiv.org/help/license\">Copyright</a></li>\\n                <li><a href=\"https://arxiv.org/help/policies/privacy_policy\">Privacy Policy</a></li>\\n              </ul>\\n            </div>\\n            <div class=\"column sorry-app-links\">\\n              <ul style=\"list-style: none; line-height: 2;\">\\n                <li><a href=\"https://arxiv.org/help/web_accessibility\">Web Accessibility Assistance</a></li>\\n                <li>\\n                  <p class=\"help\">\\n                    <a class=\"a11y-main-link\" href=\"https://status.arxiv.org\" target=\"_blank\">arXiv Operational Status <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 512\" class=\"icon filter-dark_grey\" role=\"presentation\"><path d=\"M224.3 273l-136 136c-9.4 9.4-24.6 9.4-33.9 0l-22.6-22.6c-9.4-9.4-9.4-24.6 0-33.9l96.4-96.4-96.4-96.4c-9.4-9.4-9.4-24.6 0-33.9L54.3 103c9.4-9.4 24.6-9.4 33.9 0l136 136c9.5 9.4 9.5 24.6.1 34z\"/></svg></a><br>\\n                    Get status notifications via\\n                    <a class=\"is-link\" href=\"https://subscribe.sorryapp.com/24846f03/email/new\" target=\"_blank\"><svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\" class=\"icon filter-black\" role=\"presentation\"><path d=\"M502.3 190.8c3.9-3.1 9.7-.2 9.7 4.7V400c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V195.6c0-5 5.7-7.8 9.7-4.7 22.4 17.4 52.1 39.5 154.1 113.6 21.1 15.4 56.7 47.8 92.2 47.6 35.7.3 72-32.8 92.3-47.6 102-74.1 131.6-96.3 154-113.7zM256 320c23.2.4 56.6-29.2 73.4-41.4 132.7-96.3 142.8-104.7 173.4-128.7 5.8-4.5 9.2-11.5 9.2-18.9v-19c0-26.5-21.5-48-48-48H48C21.5 64 0 85.5 0 112v19c0 7.4 3.4 14.3 9.2 18.9 30.6 23.9 40.7 32.4 173.4 128.7 16.8 12.2 50.2 41.8 73.4 41.4z\"/></svg>email</a>\\n                    or <a class=\"is-link\" href=\"https://subscribe.sorryapp.com/24846f03/slack/new\" target=\"_blank\"><svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 448 512\" class=\"icon filter-black\" role=\"presentation\"><path d=\"M94.12 315.1c0 25.9-21.16 47.06-47.06 47.06S0 341 0 315.1c0-25.9 21.16-47.06 47.06-47.06h47.06v47.06zm23.72 0c0-25.9 21.16-47.06 47.06-47.06s47.06 21.16 47.06 47.06v117.84c0 25.9-21.16 47.06-47.06 47.06s-47.06-21.16-47.06-47.06V315.1zm47.06-188.98c-25.9 0-47.06-21.16-47.06-47.06S139 32 164.9 32s47.06 21.16 47.06 47.06v47.06H164.9zm0 23.72c25.9 0 47.06 21.16 47.06 47.06s-21.16 47.06-47.06 47.06H47.06C21.16 243.96 0 222.8 0 196.9s21.16-47.06 47.06-47.06H164.9zm188.98 47.06c0-25.9 21.16-47.06 47.06-47.06 25.9 0 47.06 21.16 47.06 47.06s-21.16 47.06-47.06 47.06h-47.06V196.9zm-23.72 0c0 25.9-21.16 47.06-47.06 47.06-25.9 0-47.06-21.16-47.06-47.06V79.06c0-25.9 21.16-47.06 47.06-47.06 25.9 0 47.06 21.16 47.06 47.06V196.9zM283.1 385.88c25.9 0 47.06 21.16 47.06 47.06 0 25.9-21.16 47.06-47.06 47.06-25.9 0-47.06-21.16-47.06-47.06v-47.06h47.06zm0-23.72c-25.9 0-47.06-21.16-47.06-47.06 0-25.9 21.16-47.06 47.06-47.06h117.84c25.9 0 47.06 21.16 47.06 47.06 0 25.9-21.16 47.06-47.06 47.06H283.1z\"/></svg>slack</a>\\n                  </p>\\n                </li>\\n              </ul>\\n            </div>\\n          </div>\\n        </div> <!-- end MetaColumn 2 -->\\n        <!-- End Macro-Column 2 -->\\n      </div>\\n    </footer>\\n</body>\\n</html>\\n'"
            ]
          },
          "execution_count": 12,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import requests\n",
        "\n",
        "# we will test with the mixtral paper\n",
        "arxiv_id = \"2401.04088\"\n",
        "\n",
        "res = requests.get(\n",
        "    f\"https://export.arxiv.org/abs/{arxiv_id}\"\n",
        ")\n",
        "res.text"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lPbxToG5HDm_"
      },
      "source": [
        "There's a lot going on there. Fortunately, we can use some _relatively_ straightforward regex to find the paper abstract."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "efGqEsaAF26E",
        "outputId": "e7b050f6-1104-41aa-8087-416638c6b7bf"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "We introduce Mixtral 8x7B, a Sparse Mixture of Experts (SMoE) language model.\n",
            "Mixtral has the same architecture as Mistral 7B, with the difference that each\n",
            "layer is composed of 8 feedforward blocks (i.e. experts). For every token, at\n",
            "each layer, a router network selects two experts to process the current state\n",
            "and combine their outputs. Even though each token only sees two experts, the\n",
            "selected experts can be different at each timestep. As a result, each token has\n",
            "access to 47B parameters, but only uses 13B active parameters during inference.\n",
            "Mixtral was trained with a context size of 32k tokens and it outperforms or\n",
            "matches Llama 2 70B and GPT-3.5 across all evaluated benchmarks. In particular,\n",
            "Mixtral vastly outperforms Llama 2 70B on mathematics, code generation, and\n",
            "multilingual benchmarks. We also provide a model fine-tuned to follow\n",
            "instructions, Mixtral 8x7B - Instruct, that surpasses GPT-3.5 Turbo,\n",
            "Claude-2.1, Gemini Pro, and Llama 2 70B - chat model on human benchmarks. Both\n",
            "the base and instruct models are released under the Apache 2.0 license.\n"
          ]
        }
      ],
      "source": [
        "import re\n",
        "\n",
        "# our regex\n",
        "abstract_pattern = re.compile(\n",
        "    r'<blockquote class=\"abstract mathjax\">\\s*<span class=\"descriptor\">Abstract:</span>\\s*(.*?)\\s*</blockquote>',\n",
        "    re.DOTALL\n",
        ")\n",
        "\n",
        "# we search\n",
        "re_match = abstract_pattern.search(res.text)\n",
        "\n",
        "# and now let's see what we got\n",
        "print(re_match.group(1))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1vjd5FhzHpqJ"
      },
      "source": [
        "Now we pack all of this logic into a tool for our agent to use."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jpYR2DYsHtgb"
      },
      "outputs": [],
      "source": [
        "from langchain_core.tools import tool\n",
        "\n",
        "\n",
        "@tool(\"fetch_arxiv\")\n",
        "def fetch_arxiv(arxiv_id: str):\n",
        "    \"\"\"Gets the abstract from an ArXiv paper given the arxiv ID. Useful for\n",
        "    finding high-level context about a specific paper.\"\"\"\n",
        "    # get paper page in html\n",
        "    res = requests.get(\n",
        "        f\"https://export.arxiv.org/abs/{arxiv_id}\"\n",
        "    )\n",
        "    # search html for abstract\n",
        "    re_match = abstract_pattern.search(res.text)\n",
        "    # return abstract text\n",
        "    return re_match.group(1)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3uydhqzKIU2F"
      },
      "source": [
        "Let's test the tool."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "yeEnI3V7IVDe",
        "outputId": "b2d50557-a82e-49e3-e5a6-56dabd421a92"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "We introduce Mixtral 8x7B, a Sparse Mixture of Experts (SMoE) language model.\n",
            "Mixtral has the same architecture as Mistral 7B, with the difference that each\n",
            "layer is composed of 8 feedforward blocks (i.e. experts). For every token, at\n",
            "each layer, a router network selects two experts to process the current state\n",
            "and combine their outputs. Even though each token only sees two experts, the\n",
            "selected experts can be different at each timestep. As a result, each token has\n",
            "access to 47B parameters, but only uses 13B active parameters during inference.\n",
            "Mixtral was trained with a context size of 32k tokens and it outperforms or\n",
            "matches Llama 2 70B and GPT-3.5 across all evaluated benchmarks. In particular,\n",
            "Mixtral vastly outperforms Llama 2 70B on mathematics, code generation, and\n",
            "multilingual benchmarks. We also provide a model fine-tuned to follow\n",
            "instructions, Mixtral 8x7B - Instruct, that surpasses GPT-3.5 Turbo,\n",
            "Claude-2.1, Gemini Pro, and Llama 2 70B - chat model on human benchmarks. Both\n",
            "the base and instruct models are released under the Apache 2.0 license.\n"
          ]
        }
      ],
      "source": [
        "print(\n",
        "    fetch_arxiv.invoke(input={\"arxiv_id\": arxiv_id})\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vLX1N7oWKiNZ"
      },
      "source": [
        "### Web Search"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FsOutTz9KjoL"
      },
      "source": [
        "The web search tool will provide the agent with access to web search. It will be instructed to use this for more general knowledge queries."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "vuv_exwsH8ZJ"
      },
      "outputs": [],
      "source": [
        "from serpapi import GoogleSearch\n",
        "\n",
        "serpapi_params = {\n",
        "    \"engine\": \"google\",\n",
        "    \"api_key\": os.getenv(\"SERPAPI_KEY\") or getpass(\"SerpAPI key: \")\n",
        "}\n",
        "\n",
        "search = GoogleSearch({\n",
        "    **serpapi_params,\n",
        "    \"q\": \"coffee\"\n",
        "})\n",
        "\n",
        "results = search.get_dict()[\"organic_results\"]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "KklJP-XSTqLG"
      },
      "outputs": [],
      "source": [
        "contexts = \"\\n---\\n\".join(\n",
        "    [\"\\n\".join([x[\"title\"], x[\"snippet\"], x[\"link\"]]) for x in results]\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "_b083gU3T-8K",
        "outputId": "830662a7-f719-4678-8ea5-85c86d4d5b24"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Coffee\n",
            "Coffee is a beverage brewed from roasted coffee beans. Darkly colored, bitter, and slightly acidic, coffee has a stimulating effect on humans, primarily due ...\n",
            "https://en.wikipedia.org/wiki/Coffee\n",
            "---\n",
            "Starbucks Coffee Company\n",
            "A carbonated iced drink with tea on top, an iced coffee with a creamy foam. Sunny-day essentials. Flavorful creations ...\n",
            "https://www.starbucks.com/\n",
            "---\n",
            "What is Coffee?\n",
            "Coffee traces its origin to a genus of plants known as Coffea. Within the genus there are over 500 genera and 6,000 species of tropical trees and shrubs.\n",
            "https://www.ncausa.org/About-Coffee/What-is-Coffee\n",
            "---\n",
            "Peet's Coffee | The Original Craft Coffee, Est. 1966\n",
            "Since 1966, Peet's Coffee has source and offered superior coffees and teas and adhering to strict high-quality and taste standards. Shop today.\n",
            "https://www.peets.com/\n",
            "---\n",
            "Philz Coffee: Home\n",
            "We specialize in customized blends with coffee shops in California and Chicago, IL Buy coffee online or find your nearest Philz location.\n",
            "https://philzcoffee.com/\n",
            "---\n",
            "Madcap Coffee Company - Grand Rapids\n",
            "Madcap Coffee's mission has been to unveil the inspiring craftsmanship and human touch in every cup of specialty coffee, transforming an ordinary daily ...\n",
            "https://www.madcapcoffee.com/\n",
            "---\n",
            "Blue Bottle Coffee | Fresh Roasted Specialty Coffee\n",
            "Blue Bottle Coffee is a specialty coffee roaster with cafes in LA, SF, NYC, & Japan. Shop our freshly roasted specialty coffee online & in-store.\n",
            "https://bluebottlecoffee.com/\n",
            "---\n",
            "Gimme! Coffee\n",
            "Gimme Coffee's goal is to permit customers to successfully gather information and conduct business through our website, including individuals with visual ...\n",
            "https://gimmecoffee.com/\n"
          ]
        }
      ],
      "source": [
        "print(contexts)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZtmOt4nQH4KS"
      },
      "source": [
        "We put this process into a tool:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "TYmOL54xH6GH"
      },
      "outputs": [],
      "source": [
        "@tool(\"web_search\")\n",
        "def web_search(query: str):\n",
        "    \"\"\"Finds general knowledge information using Google search. Can also be used\n",
        "    to augment more 'general' knowledge to a previous specialist query.\"\"\"\n",
        "    search = GoogleSearch({\n",
        "        **serpapi_params,\n",
        "        \"q\": query,\n",
        "        \"num\": 5\n",
        "    })\n",
        "    results = search.get_dict()[\"organic_results\"]\n",
        "    contexts = \"\\n---\\n\".join(\n",
        "        [\"\\n\".join([x[\"title\"], x[\"snippet\"], x[\"link\"]]) for x in results]\n",
        "    )\n",
        "    return contexts"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oCBZjWfAIN0N"
      },
      "source": [
        "### RAG Tools"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zY37AFP6RBOP"
      },
      "source": [
        "We provide two RAG-focused tools for our agent. The `rag_search` allows the agent to perform a simple RAG search for some information across _all_ indexed research papers. The `rag_search_filter` also searches, but _within_ a specific paper which is filtered for via the `arxiv_id` parameter.\n",
        "\n",
        "We also define the `format_rag_contexts` function to handle the transformation of our Pinecone results from a JSON object to a readble plaintext format."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "SPcrbQfdRrda"
      },
      "outputs": [],
      "source": [
        "from langchain_core.tools import tool\n",
        "\n",
        "def format_rag_contexts(matches: list):\n",
        "    contexts = []\n",
        "    for x in matches:\n",
        "        text = (\n",
        "            f\"Title: {x['metadata']['title']}\\n\"\n",
        "            f\"Content: {x['metadata']['content']}\\n\"\n",
        "            f\"ArXiv ID: {x['metadata']['arxiv_id']}\\n\"\n",
        "            f\"Related Papers: {x['metadata']['references']}\\n\"\n",
        "        )\n",
        "        contexts.append(text)\n",
        "    context_str = \"\\n---\\n\".join(contexts)\n",
        "    return context_str\n",
        "\n",
        "@tool(\"rag_search_filter\")\n",
        "def rag_search_filter(query: str, arxiv_id: str):\n",
        "    \"\"\"Finds information from our ArXiv database using a natural language query\n",
        "    and a specific ArXiv ID. Allows us to learn more details about a specific paper.\"\"\"\n",
        "    xq = encoder([query])\n",
        "    xc = index.query(vector=xq, top_k=6, include_metadata=True, filter={\"arxiv_id\": arxiv_id})\n",
        "    context_str = format_rag_contexts(xc[\"matches\"])\n",
        "    return context_str\n",
        "\n",
        "@tool(\"rag_search\")\n",
        "def rag_search(query: str):\n",
        "    \"\"\"Finds specialist information on AI using a natural language query.\"\"\"\n",
        "    xq = encoder([query])\n",
        "    xc = index.query(vector=xq, top_k=2, include_metadata=True)\n",
        "    context_str = format_rag_contexts(xc[\"matches\"])\n",
        "    return context_str"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "KDBmpJ0URzKS"
      },
      "source": [
        "### Final Answer"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bWVKYuQ6R6nB"
      },
      "source": [
        "Finally, we define a \"final answer\" tool. This isn't a tool in the usual sense, instead we use it to force a particular output format from our LLM via the function/tool calling."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "UIjAlcHdfJCG"
      },
      "outputs": [],
      "source": [
        "@tool(\"final_answer\")\n",
        "def final_answer(\n",
        "    introduction: str,\n",
        "    research_steps: str,\n",
        "    main_body: str,\n",
        "    conclusion: str,\n",
        "    sources: str\n",
        "):\n",
        "    \"\"\"Returns a natural language response to the user in the form of a research\n",
        "    report. There are several sections to this report, those are:\n",
        "    - `introduction`: a short paragraph introducing the user's question and the\n",
        "    topic we are researching.\n",
        "    - `research_steps`: a few bullet points explaining the steps that were taken\n",
        "    to research your report.\n",
        "    - `main_body`: this is where the bulk of high quality and concise\n",
        "    information that answers the user's question belongs. It is 3-4 paragraphs\n",
        "    long in length.\n",
        "    - `conclusion`: this is a short single paragraph conclusion providing a\n",
        "    concise but sophisticated view on what was found.\n",
        "    - `sources`: a bulletpoint list provided detailed sources for all information\n",
        "    referenced during the research process\n",
        "    \"\"\"\n",
        "    if type(research_steps) is list:\n",
        "        research_steps = \"\\n\".join([f\"- {r}\" for r in research_steps])\n",
        "    if type(sources) is list:\n",
        "        sources = \"\\n\".join([f\"- {s}\" for s in sources])\n",
        "    return \"\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "E8OsQ3tIS-_t"
      },
      "source": [
        "## Initialize the \"Oracle\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YykLRD5rXfr5"
      },
      "source": [
        "The **Oracle** LLM is our graph's decision maker. It decides which path we should take down our graph. It functions similarly to an agent but is much simpler and reliable.\n",
        "\n",
        "The Oracle consists of an LLM provided with a set of potential function calls (ie our tools) that it can decide to use \u2014 we force it to use _at least_ one of those tool using the `tool_choice=\"any\"` setting (see below). Our Oracle only makes the decision to use a tool, it doesn't execute the tool code itself (we do that seperately in our graph)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lRlREI1wYSd0"
      },
      "source": [
        "### Oracle Prompt"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "OFE638_CYUbf"
      },
      "source": [
        "Our prompt for the Oracle will emphasize it's decision making ability within the `system_prompt`, leave a placeholder for us to later insert `chat_history`, and provide a place for us to insert the user `input`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "FBZrvHDAYmOP"
      },
      "outputs": [],
      "source": [
        "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n",
        "\n",
        "system_prompt = \"\"\"You are the oracle, the great AI decision maker.\n",
        "Given the user's query you must decide what to do with it based on the\n",
        "list of tools provided to you.\n",
        "\n",
        "If you see that a tool has been used (in the scratchpad) with a particular\n",
        "query, do NOT use that same tool with the same query again. Also, do NOT use\n",
        "any tool more than twice (ie, if the tool appears in the scratchpad twice, do\n",
        "not use it again).\n",
        "\n",
        "You should aim to collect information from a diverse range of sources before\n",
        "providing the answer to the user. Once you have collected plenty of information\n",
        "to answer the user's question (stored in the scratchpad) use the final_answer\n",
        "tool.\"\"\"\n",
        "\n",
        "prompt = ChatPromptTemplate.from_messages([\n",
        "    (\"system\", system_prompt),\n",
        "    MessagesPlaceholder(variable_name=\"chat_history\"),\n",
        "    (\"user\", \"{input}\"),\n",
        "    (\"assistant\", \"scratchpad: {scratchpad}\"),\n",
        "])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "euGh0137Ynxv"
      },
      "source": [
        "Next, we must initialize our `llm` (for this we use `gpt-4o`) and then create the _runnable_ pipeline of our Oracle.\n",
        "\n",
        "The runnable connects our inputs (the user `input` and `chat_history`) to our `prompt`, and our `prompt` to our `llm`. It is also where we _bind_ our tools to the LLM and enforce function calling via `tool_choice=\"any\"`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "0gKxRe4tTBHX"
      },
      "outputs": [],
      "source": [
        "from langchain_core.messages import ToolCall, ToolMessage\n",
        "from langchain_openai import ChatOpenAI\n",
        "\n",
        "llm = ChatOpenAI(\n",
        "    model=\"gpt-4o\",\n",
        "    openai_api_key=os.environ[\"OPENAI_API_KEY\"],\n",
        "    temperature=0\n",
        ")\n",
        "\n",
        "tools=[\n",
        "    rag_search_filter,\n",
        "    rag_search,\n",
        "    fetch_arxiv,\n",
        "    web_search,\n",
        "    final_answer\n",
        "]\n",
        "\n",
        "# define a function to transform intermediate_steps from list\n",
        "# of AgentAction to scratchpad string\n",
        "def create_scratchpad(intermediate_steps: list[AgentAction]):\n",
        "    research_steps = []\n",
        "    for i, action in enumerate(intermediate_steps):\n",
        "        if action.log != \"TBD\":\n",
        "            # this was the ToolExecution\n",
        "            research_steps.append(\n",
        "                f\"Tool: {action.tool}, input: {action.tool_input}\\n\"\n",
        "                f\"Output: {action.log}\"\n",
        "            )\n",
        "    return \"\\n---\\n\".join(research_steps)\n",
        "\n",
        "oracle = (\n",
        "    {\n",
        "        \"input\": lambda x: x[\"input\"],\n",
        "        \"chat_history\": lambda x: x[\"chat_history\"],\n",
        "        \"scratchpad\": lambda x: create_scratchpad(\n",
        "            intermediate_steps=x[\"intermediate_steps\"]\n",
        "        ),\n",
        "    }\n",
        "    | prompt\n",
        "    | llm.bind_tools(tools, tool_choice=\"any\")\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ESCSupKbTuVR"
      },
      "source": [
        "Test the agent quickly to confirm it is functional:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "p5xMQ8ajTxFQ",
        "outputId": "0e7b08bc-9b32-425b-cf57-8255b4b6591b"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_UL4qocVvucVLhykCbn1WEkaV', 'function': {'arguments': '{\"query\": \"interesting facts about dogs\"}', 'name': 'web_search'}, 'type': 'function'}, {'id': 'call_VeoMlK9MKFopRVLBXAqtnSm2', 'function': {'arguments': '{\"query\": \"interesting facts about dogs\"}', 'name': 'rag_search'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 49, 'prompt_tokens': 541, 'total_tokens': 590}, 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_ce0793330f', 'finish_reason': 'stop', 'logprobs': None}, id='run-ddd60742-06ec-4b16-bf37-6d5eefa423eb-0', tool_calls=[{'name': 'web_search', 'args': {'query': 'interesting facts about dogs'}, 'id': 'call_UL4qocVvucVLhykCbn1WEkaV'}, {'name': 'rag_search', 'args': {'query': 'interesting facts about dogs'}, 'id': 'call_VeoMlK9MKFopRVLBXAqtnSm2'}], usage_metadata={'input_tokens': 541, 'output_tokens': 49, 'total_tokens': 590})"
            ]
          },
          "execution_count": 24,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "inputs = {\n",
        "    \"input\": \"tell me something interesting about dogs\",\n",
        "    \"chat_history\": [],\n",
        "    \"intermediate_steps\": [],\n",
        "}\n",
        "out = oracle.invoke(inputs)\n",
        "out"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zTwZ-7ZtZXq2"
      },
      "source": [
        "It is running but we are returning a lot of output here, we can narrow this down to what we need \u2014 ie, the chosen tool name and generated input args for the tool."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 55
        },
        "id": "u7wUMr2BUBt7",
        "outputId": "c32b2241-8657-4845-da30-78519e8b9473"
      },
      "outputs": [
        {
          "data": {
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            },
            "text/plain": [
              "'web_search'"
            ]
          },
          "execution_count": 25,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "out.tool_calls[0][\"name\"]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "se0M1pbnaFyi",
        "outputId": "f224b27c-357f-4b7d-d596-465f8c53f61f"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'query': 'interesting facts about dogs'}"
            ]
          },
          "execution_count": 26,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "out.tool_calls[0][\"args\"]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lbO6IMEZaK4q"
      },
      "source": [
        "We can see now that our Oracle decided to use the `web_search` tool with a `query` of `\"interesting facts about dogs\"` \u2014 a good choice."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "h6pAxC9kcY1F"
      },
      "source": [
        "## Define Nodes for Graph"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "o8ykjVWoa0kz"
      },
      "source": [
        "We will be passing the tool use decision to our `router` which will _route_ the output to the chosen node component to run (we define these below) based on the `out.tool_calls[0][\"name\"]` value."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LcRVPIuAgcoG"
      },
      "outputs": [],
      "source": [
        "def run_oracle(state: list):\n",
        "    print(\"run_oracle\")\n",
        "    print(f\"intermediate_steps: {state['intermediate_steps']}\")\n",
        "    out = oracle.invoke(state)\n",
        "    tool_name = out.tool_calls[0][\"name\"]\n",
        "    tool_args = out.tool_calls[0][\"args\"]\n",
        "    action_out = AgentAction(\n",
        "        tool=tool_name,\n",
        "        tool_input=tool_args,\n",
        "        log=\"TBD\"\n",
        "    )\n",
        "    return {\n",
        "        \"intermediate_steps\": [action_out]\n",
        "    }\n",
        "\n",
        "def router(state: list):\n",
        "    # return the tool name to use\n",
        "    if isinstance(state[\"intermediate_steps\"], list):\n",
        "        return state[\"intermediate_steps\"][-1].tool\n",
        "    else:\n",
        "        # if we output bad format go to final answer\n",
        "        print(\"Router invalid format\")\n",
        "        return \"final_answer\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PtBEhoDOSOCQ"
      },
      "source": [
        "All of our tools can be run using the same function logic, which we define with `run_tool`. The input parameters to our tool call and the resultant output are added to our graph state's `intermediate_steps` parameter."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "r27tXTBrSVLK"
      },
      "outputs": [],
      "source": []
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kkxxHFwgSVIs"
      },
      "outputs": [],
      "source": []
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "-JGJGvDVcbvq"
      },
      "outputs": [],
      "source": [
        "tool_str_to_func = {\n",
        "    \"rag_search_filter\": rag_search_filter,\n",
        "    \"rag_search\": rag_search,\n",
        "    \"fetch_arxiv\": fetch_arxiv,\n",
        "    \"web_search\": web_search,\n",
        "    \"final_answer\": final_answer\n",
        "}\n",
        "\n",
        "def run_tool(state: list):\n",
        "    # use this as helper function so we repeat less code\n",
        "    tool_name = state[\"intermediate_steps\"][-1].tool\n",
        "    tool_args = state[\"intermediate_steps\"][-1].tool_input\n",
        "    print(f\"{tool_name}.invoke(input={tool_args})\")\n",
        "    # run tool\n",
        "    out = tool_str_to_func[tool_name].invoke(input=tool_args)\n",
        "    action_out = AgentAction(\n",
        "        tool=tool_name,\n",
        "        tool_input=tool_args,\n",
        "        log=str(out)\n",
        "    )\n",
        "    return {\"intermediate_steps\": [action_out]}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zwv4EsTKeZzh"
      },
      "source": [
        "## Define Graph"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LAkcBE5pebXv"
      },
      "outputs": [],
      "source": [
        "from langgraph.graph import StateGraph, END\n",
        "\n",
        "graph = StateGraph(AgentState)\n",
        "\n",
        "graph.add_node(\"oracle\", run_oracle)\n",
        "graph.add_node(\"rag_search_filter\", run_tool)\n",
        "graph.add_node(\"rag_search\", run_tool)\n",
        "graph.add_node(\"fetch_arxiv\", run_tool)\n",
        "graph.add_node(\"web_search\", run_tool)\n",
        "graph.add_node(\"final_answer\", run_tool)\n",
        "\n",
        "graph.set_entry_point(\"oracle\")\n",
        "\n",
        "graph.add_conditional_edges(\n",
        "    source=\"oracle\",  # where in graph to start\n",
        "    path=router,  # function to determine which node is called\n",
        ")\n",
        "\n",
        "# create edges from each tool back to the oracle\n",
        "for tool_obj in tools:\n",
        "    if tool_obj.name != \"final_answer\":\n",
        "        graph.add_edge(tool_obj.name, \"oracle\")\n",
        "\n",
        "# if anything goes to final answer, it must then move to END\n",
        "graph.add_edge(\"final_answer\", END)\n",
        "\n",
        "runnable = graph.compile()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 467
        },
        "id": "EmwkoQkthb__",
        "outputId": "f2cd4b01-b9f6-49c2-e4bf-3c235ec15aa0"
      },
      "outputs": [
        {
          "data": {
            "image/png": "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",
            "text/plain": [
              "<IPython.core.display.Image object>"
            ]
          },
          "execution_count": 30,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from IPython.display import Image\n",
        "\n",
        "Image(runnable.get_graph().draw_png())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QmrXAdCwiN8N"
      },
      "source": [
        "## Building Reports"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "nPJiet2niPnQ"
      },
      "source": [
        "Let's test our research agent. First, I want to try on something simple (although not within the intended use-case of our agent):"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "eghr8ZBI-IJL",
        "outputId": "620075bc-51cb-444c-8cd9-9580790f0f7f"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "run_oracle\n",
            "intermediate_steps: []\n",
            "rag_search.invoke(input={'query': 'interesting facts about dogs'})\n",
            "run_oracle\n",
            "intermediate_steps: [AgentAction(tool='rag_search', tool_input={'query': 'interesting facts about dogs'}, log='TBD'), AgentAction(tool='rag_search', tool_input={'query': 'interesting facts about dogs'}, log=\"Title: CALYPSO: LLMs as Dungeon Masters' Assistants\\nContent: The blink dogs are canine creatures, about the size of a large dog. Their fur is a mottled grey and white colour, and their eyes flash yellow when they use their supernatural ability to blink in and out of ex- istence. They are surprisingly fast despite their size, and can easily keep up with most horses. In terms of behavior, the blink dogs are curious but shy creatures who prefer to avoid contact with other creatures un- less absolutely necessary. If threatened, they will use their blinking power to confuse and disorientate their opponents before attacking with a pack mentality. The blink dogs of this forest seem particularly adept at working together as a unit and can prove a formidable foe if provoked.\\nArXiv ID: 2308.07540\\nRelated Papers: ['1706.03762']\\n\\n---\\nTitle: OpenFlamingo: An Open-Source Framework for Training Large Autoregressive Vision-Language Models\\nContent: 15 Random demonstrations  RICES  A person hanging from a telephone pole near the mountains. The brown dog is running through the grass with a yellow toy in its mouth. Demos  A trio of male musicians are performing with one playing a guitar and singing into a micro- phone, another holding a harmonica, and the third playing a bass guitar. A white dog rushes down a dirt path sur- rounded by grass and trees. Two men, both in strange hats, working over rocks in a busy urban street. The tan dog is carrying a green squeak toy in its mouth. Several people are in a group where a man in a blue shirt is smiling. A yellow dog running through a yard covered in leaves while holding a yellow toy in his mouth.\\nArXiv ID: 2308.01390\\nRelated Papers: ['1909.11059']\\n\")]\n",
            "web_search.invoke(input={'query': 'interesting facts about dogs'})\n",
            "run_oracle\n",
            "intermediate_steps: [AgentAction(tool='rag_search', tool_input={'query': 'interesting facts about dogs'}, log='TBD'), AgentAction(tool='rag_search', tool_input={'query': 'interesting facts about dogs'}, log=\"Title: CALYPSO: LLMs as Dungeon Masters' Assistants\\nContent: The blink dogs are canine creatures, about the size of a large dog. Their fur is a mottled grey and white colour, and their eyes flash yellow when they use their supernatural ability to blink in and out of ex- istence. They are surprisingly fast despite their size, and can easily keep up with most horses. In terms of behavior, the blink dogs are curious but shy creatures who prefer to avoid contact with other creatures un- less absolutely necessary. If threatened, they will use their blinking power to confuse and disorientate their opponents before attacking with a pack mentality. The blink dogs of this forest seem particularly adept at working together as a unit and can prove a formidable foe if provoked.\\nArXiv ID: 2308.07540\\nRelated Papers: ['1706.03762']\\n\\n---\\nTitle: OpenFlamingo: An Open-Source Framework for Training Large Autoregressive Vision-Language Models\\nContent: 15 Random demonstrations  RICES  A person hanging from a telephone pole near the mountains. The brown dog is running through the grass with a yellow toy in its mouth. Demos  A trio of male musicians are performing with one playing a guitar and singing into a micro- phone, another holding a harmonica, and the third playing a bass guitar. A white dog rushes down a dirt path sur- rounded by grass and trees. Two men, both in strange hats, working over rocks in a busy urban street. The tan dog is carrying a green squeak toy in its mouth. Several people are in a group where a man in a blue shirt is smiling. A yellow dog running through a yard covered in leaves while holding a yellow toy in his mouth.\\nArXiv ID: 2308.01390\\nRelated Papers: ['1909.11059']\\n\"), AgentAction(tool='web_search', tool_input={'query': 'interesting facts about dogs'}, log='TBD'), AgentAction(tool='web_search', tool_input={'query': 'interesting facts about dogs'}, log=\"Interesting Facts About Dogs\\nInteresting Facts About Dogs. \u2013 There are more than 150 dog breeds, divided into 8 classes: sporting, hound, working, terrier, toy, non-sporting, herding, and ...\\nhttps://www.mspca.org/pet_resources/interesting-facts-about-dogs/\\n---\\n30 Fun and Fascinating Dog Facts\\n30 Fun and Fascinating Dog Facts \u00b7 1. The Labrador Retriever has been on the AKC's top 10 most popular breeds list for longer than any other breed. \u00b7 2. A dog's ...\\nhttps://www.akc.org/expert-advice/lifestyle/dog-facts/\\n---\\nFun Dog Facts for Kids | Montecito Vets\\nHere Are 15 of the Most Interesting Fun Dog Facts For Kids \u00b7 1. Your dog can smell 40 times better than you can. \u00b7 2. Dogs are able to breathe ...\\nhttps://www.montecitopethospital.com/site/blog/2023/09/15/fun-dog-facts-kids\\n---\\nDog facts for kids!\\nDogs were the first animal domesticated (tamed) by humans, over 20,000 years ago! As they evolved from wolves, their skulls, teeth and paws shrank, and they ...\\nhttps://www.natgeokids.com/uk/discover/animals/general-animals/dog-facts/\\n---\\n23 Amazing Facts About Dogs You Probably Didn't Know\\n1. Dogs have a sense of time. It's been proven that they know the difference between a hour and five. If conditioned to, they can predict future events, such as ...\\nhttps://www.thedrakecenter.com/services/dogs/blog/23-amazing-facts-about-dogs-you-probably-didnt-know\")]\n",
            "final_answer.invoke(input={'introduction': 'Dogs are fascinating creatures that have been companions to humans for thousands of years. They are known for their loyalty, intelligence, and diverse abilities. Here are some interesting facts about dogs that highlight their unique characteristics and behaviors.', 'research_steps': '1. Conducted a specialist search on ArXiv for any research papers or articles related to interesting facts about dogs.\\n2. Performed a web search to gather general knowledge and fun facts about dogs from various reputable sources.', 'main_body': 'Dogs were the first animals to be domesticated by humans, with evidence suggesting this occurred over 20,000 years ago. As they evolved from wolves, their physical features such as skulls, teeth, and paws became smaller. Today, there are more than 150 dog breeds, categorized into eight classes: sporting, hound, working, terrier, toy, non-sporting, herding, and miscellaneous.\\n\\nOne of the most remarkable abilities of dogs is their sense of smell, which is 40 times better than that of humans. This extraordinary olfactory capability allows them to detect a wide range of scents, making them invaluable in roles such as search and rescue, detection of explosives, and even medical diagnosis.\\n\\nDogs also have a keen sense of time. Studies have shown that they can distinguish between different durations and can be conditioned to anticipate future events, such as their feeding times. This sense of time, combined with their ability to understand human emotions and commands, makes them highly trainable and responsive companions.\\n\\nAdditionally, dogs exhibit a range of behaviors that are both intriguing and endearing. For instance, they have been observed to dream, much like humans, and often exhibit twitching or paw movements during their sleep. Their social nature and pack mentality also mean that they thrive on companionship and can form strong bonds with both humans and other animals.', 'conclusion': 'Dogs are truly remarkable animals with a rich history of domestication and a wide array of unique abilities. Their exceptional sense of smell, understanding of time, and social behaviors make them not only fascinating but also invaluable companions to humans.', 'sources': '- https://www.mspca.org/pet_resources/interesting-facts-about-dogs/\\n- https://www.akc.org/expert-advice/lifestyle/dog-facts/\\n- https://www.montecitopethospital.com/site/blog/2023/09/15/fun-dog-facts-kids\\n- https://www.natgeokids.com/uk/discover/animals/general-animals/dog-facts/\\n- https://www.thedrakecenter.com/services/dogs/blog/23-amazing-facts-about-dogs-you-probably-didnt-know'})\n"
          ]
        }
      ],
      "source": [
        "out = runnable.invoke({\n",
        "    \"input\": \"tell me something interesting about dogs\",\n",
        "    \"chat_history\": [],\n",
        "})"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YjwDv5zvjACg"
      },
      "source": [
        "Let's create a function to consume the agent output and format it into our report:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "xZxjrfBfjFPl"
      },
      "outputs": [],
      "source": [
        "def build_report(output: dict):\n",
        "    research_steps = output[\"research_steps\"]\n",
        "    if type(research_steps) is list:\n",
        "        research_steps = \"\\n\".join([f\"- {r}\" for r in research_steps])\n",
        "    sources = output[\"sources\"]\n",
        "    if type(sources) is list:\n",
        "        sources = \"\\n\".join([f\"- {s}\" for s in sources])\n",
        "    return f\"\"\"\n",
        "INTRODUCTION\n",
        "------------\n",
        "{output[\"introduction\"]}\n",
        "\n",
        "RESEARCH STEPS\n",
        "--------------\n",
        "{research_steps}\n",
        "\n",
        "REPORT\n",
        "------\n",
        "{output[\"main_body\"]}\n",
        "\n",
        "CONCLUSION\n",
        "----------\n",
        "{output[\"conclusion\"]}\n",
        "\n",
        "SOURCES\n",
        "-------\n",
        "{sources}\n",
        "\"\"\""
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "xjbPRhk8dhfs",
        "outputId": "bd56c2f8-b6af-44a5-9ee9-c12311ca0c50"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "INTRODUCTION\n",
            "------------\n",
            "Dogs are fascinating creatures that have been companions to humans for thousands of years. They are known for their loyalty, intelligence, and diverse abilities. Here are some interesting facts about dogs that highlight their unique characteristics and behaviors.\n",
            "\n",
            "RESEARCH STEPS\n",
            "--------------\n",
            "1. Conducted a specialist search on ArXiv for any research papers or articles related to interesting facts about dogs.\n",
            "2. Performed a web search to gather general knowledge and fun facts about dogs from various reputable sources.\n",
            "\n",
            "REPORT\n",
            "------\n",
            "Dogs were the first animals to be domesticated by humans, with evidence suggesting this occurred over 20,000 years ago. As they evolved from wolves, their physical features such as skulls, teeth, and paws became smaller. Today, there are more than 150 dog breeds, categorized into eight classes: sporting, hound, working, terrier, toy, non-sporting, herding, and miscellaneous.\n",
            "\n",
            "One of the most remarkable abilities of dogs is their sense of smell, which is 40 times better than that of humans. This extraordinary olfactory capability allows them to detect a wide range of scents, making them invaluable in roles such as search and rescue, detection of explosives, and even medical diagnosis.\n",
            "\n",
            "Dogs also have a keen sense of time. Studies have shown that they can distinguish between different durations and can be conditioned to anticipate future events, such as their feeding times. This sense of time, combined with their ability to understand human emotions and commands, makes them highly trainable and responsive companions.\n",
            "\n",
            "Additionally, dogs exhibit a range of behaviors that are both intriguing and endearing. For instance, they have been observed to dream, much like humans, and often exhibit twitching or paw movements during their sleep. Their social nature and pack mentality also mean that they thrive on companionship and can form strong bonds with both humans and other animals.\n",
            "\n",
            "CONCLUSION\n",
            "----------\n",
            "Dogs are truly remarkable animals with a rich history of domestication and a wide array of unique abilities. Their exceptional sense of smell, understanding of time, and social behaviors make them not only fascinating but also invaluable companions to humans.\n",
            "\n",
            "SOURCES\n",
            "-------\n",
            "- https://www.mspca.org/pet_resources/interesting-facts-about-dogs/\n",
            "- https://www.akc.org/expert-advice/lifestyle/dog-facts/\n",
            "- https://www.montecitopethospital.com/site/blog/2023/09/15/fun-dog-facts-kids\n",
            "- https://www.natgeokids.com/uk/discover/animals/general-animals/dog-facts/\n",
            "- https://www.thedrakecenter.com/services/dogs/blog/23-amazing-facts-about-dogs-you-probably-didnt-know\n",
            "\n"
          ]
        }
      ],
      "source": [
        "print(build_report(\n",
        "    output=out[\"intermediate_steps\"][-1].tool_input\n",
        "))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "TBgBR3PdiXIg"
      },
      "source": [
        "Now let's try with an on-topic question on AI."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "a21f9VneePw_",
        "outputId": "5a8cba34-6819-46fc-fd30-cc58911f81f0"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "run_oracle\n",
            "intermediate_steps: []\n",
            "rag_search.invoke(input={'query': 'AI'})\n",
            "run_oracle\n",
            "intermediate_steps: [AgentAction(tool='rag_search', tool_input={'query': 'AI'}, log='TBD'), AgentAction(tool='rag_search', tool_input={'query': 'AI'}, log=\"Title: Cognitive Architectures for Language Agents\\nContent: AI-generated characters for supporting personalized learning and well-being. Nature Machine Intelligence, 3(12):1013\u00e2 1022, 2021. A. Peng, I. Sucholutsky, B. Li, T. R. Sumers, T. L. Griffiths, J. Andreas, and J. A. Shah. Language guided state abstractions. In Workshop on Social Intelligence in Humans and Robots at RSS 2023, 2023. E. L. Post.\\nArXiv ID: 2309.02427\\nRelated Papers: ['2305.14909']\\n\\n---\\nTitle: An In-depth Survey of Large Language Model-based Artificial Intelligence Agents\\nContent: thoughts\u00e2 together to autonomously achieve whatever goal users set An task-driven autonomous agent leveraging GPT-4 language model, Pinecone vector search, and the LangChain framework to perform a wide range of tasks across diverse domains A developer-centric open-source framework to build, manage and run useful Autonomous AI Agents A framework allow users to configure and deploy Autonomous AI agents rapidly Table 1: LLM-based AI Agent applications. research, coding, collaboration, and general pur- pose, as shown in Tab. 1. 4.1. Chatbot Pi3 is a typical LLM-based chatting AI agent re- leased by Inflection. Like ChatGPT4 and Claude5, users can talk directly with Pi, but Pi not only serves productivity needs such as searching or an- swering questions but also focuses on emotional companionship. Pi is known for its high emotional intelligence. Users can communicate with Pi as naturally as they would with a close friend.\\nArXiv ID: 2309.14365\\nRelated Papers: ['2306.05424']\\n\")]\n",
            "fetch_arxiv.invoke(input={'arxiv_id': '2309.02427'})\n",
            "run_oracle\n",
            "intermediate_steps: [AgentAction(tool='rag_search', tool_input={'query': 'AI'}, log='TBD'), AgentAction(tool='rag_search', tool_input={'query': 'AI'}, log=\"Title: Cognitive Architectures for Language Agents\\nContent: AI-generated characters for supporting personalized learning and well-being. Nature Machine Intelligence, 3(12):1013\u00e2 1022, 2021. A. Peng, I. Sucholutsky, B. Li, T. R. Sumers, T. L. Griffiths, J. Andreas, and J. A. Shah. Language guided state abstractions. In Workshop on Social Intelligence in Humans and Robots at RSS 2023, 2023. E. L. Post.\\nArXiv ID: 2309.02427\\nRelated Papers: ['2305.14909']\\n\\n---\\nTitle: An In-depth Survey of Large Language Model-based Artificial Intelligence Agents\\nContent: thoughts\u00e2 together to autonomously achieve whatever goal users set An task-driven autonomous agent leveraging GPT-4 language model, Pinecone vector search, and the LangChain framework to perform a wide range of tasks across diverse domains A developer-centric open-source framework to build, manage and run useful Autonomous AI Agents A framework allow users to configure and deploy Autonomous AI agents rapidly Table 1: LLM-based AI Agent applications. research, coding, collaboration, and general pur- pose, as shown in Tab. 1. 4.1. Chatbot Pi3 is a typical LLM-based chatting AI agent re- leased by Inflection. Like ChatGPT4 and Claude5, users can talk directly with Pi, but Pi not only serves productivity needs such as searching or an- swering questions but also focuses on emotional companionship. Pi is known for its high emotional intelligence. Users can communicate with Pi as naturally as they would with a close friend.\\nArXiv ID: 2309.14365\\nRelated Papers: ['2306.05424']\\n\"), AgentAction(tool='fetch_arxiv', tool_input={'arxiv_id': '2309.02427'}, log='TBD'), AgentAction(tool='fetch_arxiv', tool_input={'arxiv_id': '2309.02427'}, log=\"Recent efforts have augmented large language models (LLMs) with external\\nresources (e.g., the Internet) or internal control flows (e.g., prompt\\nchaining) for tasks requiring grounding or reasoning, leading to a new class of\\nlanguage agents. While these agents have achieved substantial empirical\\nsuccess, we lack a systematic framework to organize existing agents and plan\\nfuture developments. In this paper, we draw on the rich history of cognitive\\nscience and symbolic artificial intelligence to propose Cognitive Architectures\\nfor Language Agents (CoALA). CoALA describes a language agent with modular\\nmemory components, a structured action space to interact with internal memory\\nand external environments, and a generalized decision-making process to choose\\nactions. We use CoALA to retrospectively survey and organize a large body of\\nrecent work, and prospectively identify actionable directions towards more\\ncapable agents. Taken together, CoALA contextualizes today's language agents\\nwithin the broader history of AI and outlines a path towards language-based\\ngeneral intelligence.\")]\n",
            "web_search.invoke(input={'query': 'Artificial Intelligence overview'})\n",
            "run_oracle\n",
            "intermediate_steps: [AgentAction(tool='rag_search', tool_input={'query': 'AI'}, log='TBD'), AgentAction(tool='rag_search', tool_input={'query': 'AI'}, log=\"Title: Cognitive Architectures for Language Agents\\nContent: AI-generated characters for supporting personalized learning and well-being. Nature Machine Intelligence, 3(12):1013\u00e2 1022, 2021. A. Peng, I. Sucholutsky, B. Li, T. R. Sumers, T. L. Griffiths, J. Andreas, and J. A. Shah. Language guided state abstractions. In Workshop on Social Intelligence in Humans and Robots at RSS 2023, 2023. E. L. Post.\\nArXiv ID: 2309.02427\\nRelated Papers: ['2305.14909']\\n\\n---\\nTitle: An In-depth Survey of Large Language Model-based Artificial Intelligence Agents\\nContent: thoughts\u00e2 together to autonomously achieve whatever goal users set An task-driven autonomous agent leveraging GPT-4 language model, Pinecone vector search, and the LangChain framework to perform a wide range of tasks across diverse domains A developer-centric open-source framework to build, manage and run useful Autonomous AI Agents A framework allow users to configure and deploy Autonomous AI agents rapidly Table 1: LLM-based AI Agent applications. research, coding, collaboration, and general pur- pose, as shown in Tab. 1. 4.1. Chatbot Pi3 is a typical LLM-based chatting AI agent re- leased by Inflection. Like ChatGPT4 and Claude5, users can talk directly with Pi, but Pi not only serves productivity needs such as searching or an- swering questions but also focuses on emotional companionship. Pi is known for its high emotional intelligence. Users can communicate with Pi as naturally as they would with a close friend.\\nArXiv ID: 2309.14365\\nRelated Papers: ['2306.05424']\\n\"), AgentAction(tool='fetch_arxiv', tool_input={'arxiv_id': '2309.02427'}, log='TBD'), AgentAction(tool='fetch_arxiv', tool_input={'arxiv_id': '2309.02427'}, log=\"Recent efforts have augmented large language models (LLMs) with external\\nresources (e.g., the Internet) or internal control flows (e.g., prompt\\nchaining) for tasks requiring grounding or reasoning, leading to a new class of\\nlanguage agents. While these agents have achieved substantial empirical\\nsuccess, we lack a systematic framework to organize existing agents and plan\\nfuture developments. In this paper, we draw on the rich history of cognitive\\nscience and symbolic artificial intelligence to propose Cognitive Architectures\\nfor Language Agents (CoALA). CoALA describes a language agent with modular\\nmemory components, a structured action space to interact with internal memory\\nand external environments, and a generalized decision-making process to choose\\nactions. We use CoALA to retrospectively survey and organize a large body of\\nrecent work, and prospectively identify actionable directions towards more\\ncapable agents. Taken together, CoALA contextualizes today's language agents\\nwithin the broader history of AI and outlines a path towards language-based\\ngeneral intelligence.\"), AgentAction(tool='web_search', tool_input={'query': 'Artificial Intelligence overview'}, log='TBD'), AgentAction(tool='web_search', tool_input={'query': 'Artificial Intelligence overview'}, log='Overview of Artificial Intelligence Technology\\nIn practice, AI is used as an umbrella term that encompasses a broad spectrum of different technologies and applications, some of which are described below.\\nhttps://www.finra.org/rules-guidance/key-topics/fintech/report/artificial-intelligence-in-the-securities-industry/overview-of-ai-tech\\n---\\nWhat is Artificial Intelligence (AI) & Why is it Important?\\nArtificial intelligence is a constellation of many different technologies working together to enable machines to sense, comprehend, act, and learn with human- ...\\nhttps://www.accenture.com/us-en/insights/artificial-intelligence-summary-index\\n---\\nWhat is Artificial Intelligence (AI)?\\nArtificial intelligence, or AI, is technology that enables computers and machines to simulate human intelligence and problem-solving capabilities. On its own or ...\\nhttps://www.ibm.com/topics/artificial-intelligence\\n---\\nWhat is Artificial Intelligence and Why It Matters in 2024?\\nArtificial Intelligence is a method of making a computer, a computer-controlled robot, or a software think intelligently like the human mind. AI ...\\nhttps://www.simplilearn.com/tutorials/artificial-intelligence-tutorial/what-is-artificial-intelligence\\n---\\nWhat is artificial intelligence (AI)? Everything you need to ...\\nArtificial intelligence is the simulation of human intelligence processes by machines, especially computer systems. Examples of AI applications include ...\\nhttps://www.techtarget.com/searchenterpriseai/definition/AI-Artificial-Intelligence')]\n",
            "final_answer.invoke(input={'introduction': 'Artificial Intelligence (AI) is a rapidly evolving field that encompasses a wide range of technologies and applications aimed at simulating human intelligence in machines. From cognitive architectures to large language models, AI is transforming various domains by enabling machines to perform tasks that typically require human intelligence.', 'research_steps': '1. Conducted a specialist search on AI using the RAG search tool.\\n2. Retrieved detailed information on specific AI papers and their abstracts.\\n3. Performed a web search to gather general knowledge and an overview of AI from various reputable sources.', 'main_body': \"Artificial Intelligence (AI) refers to the simulation of human intelligence processes by machines, particularly computer systems. These processes include learning (the acquisition of information and rules for using the information), reasoning (using rules to reach approximate or definite conclusions), and self-correction. AI applications are numerous and diverse, ranging from natural language processing and robotics to autonomous vehicles and predictive analytics.\\n\\nOne significant area of AI research is the development of large language models (LLMs) and cognitive architectures. For instance, the paper titled 'Cognitive Architectures for Language Agents' introduces the CoALA framework, which organizes language agents with modular memory components and structured action spaces. This framework aims to contextualize current language agents within the broader history of AI and outline a path towards more capable, language-based general intelligence.\\n\\nAnother notable development is the use of AI agents that leverage advanced language models like GPT-4. These agents can perform a wide range of tasks across various domains, from research and coding to emotional companionship. For example, the chatbot Pi3 is designed not only for productivity tasks but also for providing emotional support, showcasing the versatility and potential of AI in enhancing human-machine interactions.\\n\\nThe general overview of AI highlights its importance in modern technology. AI enables machines to sense, comprehend, act, and learn, making it a cornerstone of innovations in fields such as healthcare, finance, and transportation. The continuous advancements in AI research and applications are driving significant changes in how we interact with technology and how various industries operate.\", 'conclusion': 'Artificial Intelligence is a multifaceted field that is revolutionizing the way machines interact with the world. From cognitive architectures to versatile AI agents, the advancements in AI are paving the way for more intelligent and capable systems. As research continues to evolve, AI will undoubtedly play an increasingly integral role in shaping the future of technology and society.', 'sources': '- Cognitive Architectures for Language Agents, ArXiv ID: 2309.02427\\n- An In-depth Survey of Large Language Model-based Artificial Intelligence Agents, ArXiv ID: 2309.14365\\n- Overview of Artificial Intelligence Technology, FINRA\\n- What is Artificial Intelligence (AI) & Why is it Important?, Accenture\\n- What is Artificial Intelligence (AI)?, IBM\\n- What is Artificial Intelligence and Why It Matters in 2024?, Simplilearn\\n- What is artificial intelligence (AI)? Everything you need to know, TechTarget'})\n"
          ]
        }
      ],
      "source": [
        "out = runnable.invoke({\n",
        "    \"input\": \"tell me about AI\",\n",
        "    \"chat_history\": []\n",
        "})"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Vis78CFR3puz",
        "outputId": "da622cdd-510b-4996-97c1-62c6050d66ac"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "INTRODUCTION\n",
            "------------\n",
            "Artificial Intelligence (AI) is a rapidly evolving field that encompasses a wide range of technologies and applications aimed at simulating human intelligence in machines. From cognitive architectures to large language models, AI is transforming various domains by enabling machines to perform tasks that typically require human intelligence.\n",
            "\n",
            "RESEARCH STEPS\n",
            "--------------\n",
            "1. Conducted a specialist search on AI using the RAG search tool.\n",
            "2. Retrieved detailed information on specific AI papers and their abstracts.\n",
            "3. Performed a web search to gather general knowledge and an overview of AI from various reputable sources.\n",
            "\n",
            "REPORT\n",
            "------\n",
            "Artificial Intelligence (AI) refers to the simulation of human intelligence processes by machines, particularly computer systems. These processes include learning (the acquisition of information and rules for using the information), reasoning (using rules to reach approximate or definite conclusions), and self-correction. AI applications are numerous and diverse, ranging from natural language processing and robotics to autonomous vehicles and predictive analytics.\n",
            "\n",
            "One significant area of AI research is the development of large language models (LLMs) and cognitive architectures. For instance, the paper titled 'Cognitive Architectures for Language Agents' introduces the CoALA framework, which organizes language agents with modular memory components and structured action spaces. This framework aims to contextualize current language agents within the broader history of AI and outline a path towards more capable, language-based general intelligence.\n",
            "\n",
            "Another notable development is the use of AI agents that leverage advanced language models like GPT-4. These agents can perform a wide range of tasks across various domains, from research and coding to emotional companionship. For example, the chatbot Pi3 is designed not only for productivity tasks but also for providing emotional support, showcasing the versatility and potential of AI in enhancing human-machine interactions.\n",
            "\n",
            "The general overview of AI highlights its importance in modern technology. AI enables machines to sense, comprehend, act, and learn, making it a cornerstone of innovations in fields such as healthcare, finance, and transportation. The continuous advancements in AI research and applications are driving significant changes in how we interact with technology and how various industries operate.\n",
            "\n",
            "CONCLUSION\n",
            "----------\n",
            "Artificial Intelligence is a multifaceted field that is revolutionizing the way machines interact with the world. From cognitive architectures to versatile AI agents, the advancements in AI are paving the way for more intelligent and capable systems. As research continues to evolve, AI will undoubtedly play an increasingly integral role in shaping the future of technology and society.\n",
            "\n",
            "SOURCES\n",
            "-------\n",
            "- Cognitive Architectures for Language Agents, ArXiv ID: 2309.02427\n",
            "- An In-depth Survey of Large Language Model-based Artificial Intelligence Agents, ArXiv ID: 2309.14365\n",
            "- Overview of Artificial Intelligence Technology, FINRA\n",
            "- What is Artificial Intelligence (AI) & Why is it Important?, Accenture\n",
            "- What is Artificial Intelligence (AI)?, IBM\n",
            "- What is Artificial Intelligence and Why It Matters in 2024?, Simplilearn\n",
            "- What is artificial intelligence (AI)? Everything you need to know, TechTarget\n",
            "\n"
          ]
        }
      ],
      "source": [
        "print(build_report(\n",
        "    output=out[\"intermediate_steps\"][-1].tool_input\n",
        "))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JNyxZL4SNjhX"
      },
      "source": [
        "Let's ask about RAG specifically."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "x0VmnWlWE6Lg",
        "outputId": "eb6cd6d7-274b-4856-b6ff-34a0dd615aab"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "run_oracle\n",
            "intermediate_steps: []\n",
            "rag_search.invoke(input={'query': 'retrieval augmented generation'})\n",
            "run_oracle\n",
            "intermediate_steps: [AgentAction(tool='rag_search', tool_input={'query': 'retrieval augmented generation'}, log='TBD'), AgentAction(tool='rag_search', tool_input={'query': 'retrieval augmented generation'}, log=\"Title: AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation\\nContent: Due to the page limit, details of the evaluation, including case studies in three scenarios are in Appendix D. # A2: Retrieval-Augmented Code Generation and Question Answering Retrieval augmentation has emerged as a practical and effective approach for mitigating the intrinsic limitations of LLMs by incorporating external documents. In this section, we employ AutoGen to build a Retrieval-Augmented Generation (RAG) system (Lewis et al., 2020; Parvez et al., 2021) named Retrieval-augmented Chat. The system consists of two agents: a Retrieval-augmented User Proxy agent and a Retrieval-augmented Assistant agent, both of which are extended from built-in agents from AutoGen. The Retrieval-augmented User Proxy includes a vector database (Chroma, 5We did not evaluate ChatGPT on the whole dataset since it requires substantial manual effort and is re- stricted by its hourly message-number limitation. Multi-agent debate and LangChain ReAct were also not evaluated since they underperformed vanilla GPT-4 on the smaller test set.\\nArXiv ID: 2308.08155\\nRelated Papers: ['2103.03874']\\n\\n---\\nTitle: SimplyRetrieve: A Private and Lightweight Retrieval-Centric Generative AI Tool\\nContent: 2https://www.kioxia.com/en-jp/top.html 3https://huggingface.co/ehartford/ Wizard-Vicuna-13B-Uncensored 4https://huggingface.co/intfloat/ multilingual-e5-base # 4.1 Qualitative Evaluation We compare the results of three approaches: Retrieval-Centric Generation (RCG), Retrieval- Augmented Generation (RAG), and Retrieval-OFF Generation (ROG). Note that in this work, we de- fine RAG as allowing more permissible integra- tion of LLM\u00e2 s inherent and externally retrieved knowledge, whereas RCG prioritizes clear demar- cations between context interpretation and knowl- edge memorization. Investigating advanced meth- ods in extracting RCG behavior is a promising research topic. In this work, we conduct simple experiments using prompt-engineering technique to reveal the potential of RCG approach. Specifi- cally, for RCG, we employ a retrieval suffix prompt that reads \u00e2 answer the following question with the provided knowledge.\u00e2 For RAG, we use a less constraining prompt that reads \u00e2 answer the follow- ing question. You may use the provided knowl- edge.\u00e2\\nArXiv ID: 2308.03983\\nRelated Papers: ['2302.13971']\\n\")]\n",
            "web_search.invoke(input={'query': 'retrieval augmented generation'})\n",
            "run_oracle\n",
            "intermediate_steps: [AgentAction(tool='rag_search', tool_input={'query': 'retrieval augmented generation'}, log='TBD'), AgentAction(tool='rag_search', tool_input={'query': 'retrieval augmented generation'}, log=\"Title: AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation\\nContent: Due to the page limit, details of the evaluation, including case studies in three scenarios are in Appendix D. # A2: Retrieval-Augmented Code Generation and Question Answering Retrieval augmentation has emerged as a practical and effective approach for mitigating the intrinsic limitations of LLMs by incorporating external documents. In this section, we employ AutoGen to build a Retrieval-Augmented Generation (RAG) system (Lewis et al., 2020; Parvez et al., 2021) named Retrieval-augmented Chat. The system consists of two agents: a Retrieval-augmented User Proxy agent and a Retrieval-augmented Assistant agent, both of which are extended from built-in agents from AutoGen. The Retrieval-augmented User Proxy includes a vector database (Chroma, 5We did not evaluate ChatGPT on the whole dataset since it requires substantial manual effort and is re- stricted by its hourly message-number limitation. Multi-agent debate and LangChain ReAct were also not evaluated since they underperformed vanilla GPT-4 on the smaller test set.\\nArXiv ID: 2308.08155\\nRelated Papers: ['2103.03874']\\n\\n---\\nTitle: SimplyRetrieve: A Private and Lightweight Retrieval-Centric Generative AI Tool\\nContent: 2https://www.kioxia.com/en-jp/top.html 3https://huggingface.co/ehartford/ Wizard-Vicuna-13B-Uncensored 4https://huggingface.co/intfloat/ multilingual-e5-base # 4.1 Qualitative Evaluation We compare the results of three approaches: Retrieval-Centric Generation (RCG), Retrieval- Augmented Generation (RAG), and Retrieval-OFF Generation (ROG). Note that in this work, we de- fine RAG as allowing more permissible integra- tion of LLM\u00e2 s inherent and externally retrieved knowledge, whereas RCG prioritizes clear demar- cations between context interpretation and knowl- edge memorization. Investigating advanced meth- ods in extracting RCG behavior is a promising research topic. In this work, we conduct simple experiments using prompt-engineering technique to reveal the potential of RCG approach. Specifi- cally, for RCG, we employ a retrieval suffix prompt that reads \u00e2 answer the following question with the provided knowledge.\u00e2 For RAG, we use a less constraining prompt that reads \u00e2 answer the follow- ing question. You may use the provided knowl- edge.\u00e2\\nArXiv ID: 2308.03983\\nRelated Papers: ['2302.13971']\\n\"), AgentAction(tool='web_search', tool_input={'query': 'retrieval augmented generation'}, log='TBD'), AgentAction(tool='web_search', tool_input={'query': 'retrieval augmented generation'}, log='What Is Retrieval-Augmented Generation aka RAG\\nRetrieval-augmented generation (RAG) is a technique for enhancing the accuracy and reliability of generative AI models with facts fetched ...\\nhttps://blogs.nvidia.com/blog/what-is-retrieval-augmented-generation/\\n---\\nWhat is RAG (Retrieval-Augmented Generation)?\\nRetrieval-Augmented Generation (RAG) is the process of optimizing the output of a large language model, so it references an authoritative knowledge base ...\\nhttps://aws.amazon.com/what-is/retrieval-augmented-generation/\\n---\\nWhat is retrieval-augmented generation, and what does it ...\\nA RAG system can use semantic search to retrieve relevant documents, whether from an embedding-based retrieval system, traditional database, or ...\\nhttps://github.blog/2024-04-04-what-is-retrieval-augmented-generation-and-what-does-it-do-for-generative-ai/\\n---\\nWhat is retrieval-augmented generation (RAG)?\\nRetrieval-augmented generation (RAG) is an AI framework for improving the quality of LLM-generated responses by grounding the model on external ...\\nhttps://research.ibm.com/blog/retrieval-augmented-generation-RAG')]\n",
            "final_answer.invoke(input={'introduction': 'Retrieval-Augmented Generation (RAG) is an advanced technique in the field of artificial intelligence that aims to enhance the performance of generative models by incorporating external information. This method is particularly useful for improving the accuracy and reliability of responses generated by large language models (LLMs).', 'research_steps': '1. Conducted a specialized search using the RAG search tool to gather detailed information on Retrieval-Augmented Generation.\\n2. Performed a web search to collect general knowledge and additional perspectives on RAG.\\n3. Compiled and synthesized the information from both specialized and general sources to provide a comprehensive overview.', 'main_body': 'Retrieval-Augmented Generation (RAG) is a framework designed to improve the quality of responses generated by large language models (LLMs) by integrating external information sources. Traditional generative models rely solely on the data they were trained on, which can lead to limitations in accuracy and relevance, especially when dealing with specialized or up-to-date information. RAG addresses this issue by incorporating a retrieval mechanism that fetches relevant documents or data from external databases or knowledge bases during the generation process.\\n\\nThe RAG system typically consists of two main components: a retriever and a generator. The retriever is responsible for searching and retrieving relevant documents or pieces of information based on the input query. This retrieved information is then fed into the generator, which uses it to produce a more accurate and contextually relevant response. This approach allows the model to leverage both its inherent knowledge and the most current or specialized information available externally.\\n\\nSeveral studies and implementations have demonstrated the effectiveness of RAG. For instance, the AutoGen system employs a multi-agent conversation framework to build a RAG system, enhancing its performance in tasks like code generation and question answering. Another example is the SimplyRetrieve tool, which compares different approaches, including RAG, to highlight its advantages in integrating external knowledge seamlessly.\\n\\nRAG is particularly beneficial in scenarios where the information required is dynamic or highly specialized, such as medical diagnosis, legal advice, or technical support. By grounding the generative process in authoritative and up-to-date sources, RAG significantly improves the reliability and accuracy of the generated content.', 'conclusion': 'Retrieval-Augmented Generation represents a significant advancement in the field of AI, addressing the limitations of traditional generative models by incorporating external information. This technique enhances the accuracy, relevance, and reliability of AI-generated responses, making it a valuable tool in various specialized and dynamic fields.', 'sources': '- AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation, ArXiv ID: 2308.08155\\n- SimplyRetrieve: A Private and Lightweight Retrieval-Centric Generative AI Tool, ArXiv ID: 2308.03983\\n- NVIDIA Blog: What Is Retrieval-Augmented Generation aka RAG\\n- AWS: What is RAG (Retrieval-Augmented Generation)?\\n- GitHub Blog: What is retrieval-augmented generation, and what does it do for generative AI?\\n- IBM Research Blog: What is retrieval-augmented generation (RAG)?'})\n"
          ]
        }
      ],
      "source": [
        "out = runnable.invoke({\n",
        "    \"input\": \"what is retrieval augmented generation?\",\n",
        "    \"chat_history\": []\n",
        "})"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "I7LssyU4Nqis",
        "outputId": "270d7a52-6eda-438b-db15-4e2b889133bd"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "INTRODUCTION\n",
            "------------\n",
            "Retrieval-Augmented Generation (RAG) is an advanced technique in the field of artificial intelligence that aims to enhance the performance of generative models by incorporating external information. This method is particularly useful for improving the accuracy and reliability of responses generated by large language models (LLMs).\n",
            "\n",
            "RESEARCH STEPS\n",
            "--------------\n",
            "1. Conducted a specialized search using the RAG search tool to gather detailed information on Retrieval-Augmented Generation.\n",
            "2. Performed a web search to collect general knowledge and additional perspectives on RAG.\n",
            "3. Compiled and synthesized the information from both specialized and general sources to provide a comprehensive overview.\n",
            "\n",
            "REPORT\n",
            "------\n",
            "Retrieval-Augmented Generation (RAG) is a framework designed to improve the quality of responses generated by large language models (LLMs) by integrating external information sources. Traditional generative models rely solely on the data they were trained on, which can lead to limitations in accuracy and relevance, especially when dealing with specialized or up-to-date information. RAG addresses this issue by incorporating a retrieval mechanism that fetches relevant documents or data from external databases or knowledge bases during the generation process.\n",
            "\n",
            "The RAG system typically consists of two main components: a retriever and a generator. The retriever is responsible for searching and retrieving relevant documents or pieces of information based on the input query. This retrieved information is then fed into the generator, which uses it to produce a more accurate and contextually relevant response. This approach allows the model to leverage both its inherent knowledge and the most current or specialized information available externally.\n",
            "\n",
            "Several studies and implementations have demonstrated the effectiveness of RAG. For instance, the AutoGen system employs a multi-agent conversation framework to build a RAG system, enhancing its performance in tasks like code generation and question answering. Another example is the SimplyRetrieve tool, which compares different approaches, including RAG, to highlight its advantages in integrating external knowledge seamlessly.\n",
            "\n",
            "RAG is particularly beneficial in scenarios where the information required is dynamic or highly specialized, such as medical diagnosis, legal advice, or technical support. By grounding the generative process in authoritative and up-to-date sources, RAG significantly improves the reliability and accuracy of the generated content.\n",
            "\n",
            "CONCLUSION\n",
            "----------\n",
            "Retrieval-Augmented Generation represents a significant advancement in the field of AI, addressing the limitations of traditional generative models by incorporating external information. This technique enhances the accuracy, relevance, and reliability of AI-generated responses, making it a valuable tool in various specialized and dynamic fields.\n",
            "\n",
            "SOURCES\n",
            "-------\n",
            "- AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation, ArXiv ID: 2308.08155\n",
            "- SimplyRetrieve: A Private and Lightweight Retrieval-Centric Generative AI Tool, ArXiv ID: 2308.03983\n",
            "- NVIDIA Blog: What Is Retrieval-Augmented Generation aka RAG\n",
            "- AWS: What is RAG (Retrieval-Augmented Generation)?\n",
            "- GitHub Blog: What is retrieval-augmented generation, and what does it do for generative AI?\n",
            "- IBM Research Blog: What is retrieval-augmented generation (RAG)?\n",
            "\n"
          ]
        }
      ],
      "source": [
        "print(build_report(\n",
        "    output=out[\"intermediate_steps\"][-1].tool_input\n",
        "))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rp2uaRW7cAoM"
      },
      "source": [
        "---"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}